2016-04-26 31 views
3

我在評估Java選項時遇到了一些麻煩。請看下面的測試:Java可選評估副作用

@Test 
public void test() { 
    System.out.println("GOT STRING: " + first().orElse(second())); 
} 

private Optional<String> first() { 
    System.out.println("Evaluating first"); 
    return Optional.of("STRING OPTIONAL"); 
} 

private String second() { 
    System.out.println("Evaluating second"); 
    return "SECOND STRING"; 
} 

我的期望是,由於第()返回一個非空可選,即二是不進行評估。但事實上,輸出是:

Evaluating first 
Evaluating second 
GOT STRING: STRING OPTIONAL 

試圖在測試中使用否則容易的功能:

@Test 
public void test2() { 
    System.out.println("GOT STRING: " + (first() != null ? "FIRST IS NOT NULL" : second())); 
} 

輸出:

Evaluating first 
GOT STRING: FIRST IS NOT NULL 

爲什麼第二個選項評估?這似乎很糟糕?

+0

如果調用'否則容易(...)'然後說法肯定會進行評估。也許你想'orElseGet(...)'接受一個它需要時調用的函數。 – khelwood

+0

當你的代碼中沒有任何lambda表達式時,爲什麼你的問題用「lambda」標記? –

+0

由於googling總是給lamdas,而orElseGet通常與lamda構造一起使用。 –

回答

4

爲什麼要評估第二個選項?

因爲您正在調用second()方法,所以要將該值作爲參數提供給orElse()。參數的值將被忽略(因爲您已經有一個值),但這並不意味着它不必提供。

基本上,這個代碼:

first().orElse(second()) 

等同於:

Optional<String> tmp1 = first(); 
Optional<String> tmp2 = second(); 
Optional<String> result = tmp1.orElse(tmp2); 

沒有什麼具體可選,在這裏 - 這是爭論如何評價總是作品在Java中。

注意,這是一個結構(orElse)和條件操作語言之間有很大的區別結構(?:),這隻會評估或者第二第三個操作數,但不可能兼顧。

如阿圖爾提到的,如果你想調用推遲到second(),你需要使用orElseGet,在那裏你傳遞參數是不是要使用的值,如果first沒有之一,但呼盡在以得到的值。

+0

我看了使用這種語言結構的orElse的實現。所以我應該表現出相同的效果。但你的解釋適合這裏。這對我來說仍然是一個容易出錯的原因,應該記錄下來。雖然你對評估是正確的。我有點忘記了使用該功能。 –

9

它被評估,因爲您按值傳遞值爲second(),而不僅僅是傳遞函數本身的引用。您需要執行以下操作之一:

System.out.println("GOT STRING: " + first().orElseGet(() ->second())); 
System.out.println("GOT STRING: " + first().orElseGet(this::second)); 

延遲評估直至真正需要。

2

由於second()調用作爲參數傳遞給方法orElse,參數在Java中被熱切地評估。

如果您需要提供一個供應商或避免急於執行,你可以使用orElseGet一個希望將Supplier

optional.orElseGet(()->second()))