2015-04-17 68 views
7

昨天我絆了什麼我也不很懂,也不是我能找到的解釋:差()在Java 8

考慮以下操作:

Stream.of(1, 2, 3).map(i -> i * 2).forEach(System.out::println); 

//This one won't compile 
Stream.of(1, 2, 3).map(i -> { i * 2; }).forEach(System.out::println); 

看來,第二個可以擴展到

Stream.of(1, 2, 3).map(i -> { return i * 2;}).forEach(System.out::println); 

,它只會編譯罰款。我想出了這個,因爲我有點習慣於第一個版本,但我的IDE(Netbeans)總是指最後一個版本。

所以我的問題是:什麼是這兩個實現的區別/優勢?爲什麼{}模塊需要返回值?這個值的需求在哪裏(編譯代碼除外)?

更新:

對於When are braces optional in Java 8 lambda syntax?,這一個不能對lambda表達式的語法,只是因爲

Stream.of(1, 2, 3).forEach(i -> { System.out.println(i); }); 

編譯罰款,所以必須是(從我understading)約執行map()

乾杯,本

+1

「無支撐」版本要求箭頭符號的右側是一個有效的Java表達式(注意:expression,not statement!);這是它工作的原因。但最後都做同樣的事情。 – fge

回答

9

所不同的是以下內容:

lambda表達式看起來像

parameters -> expression 

parameters -> { block } 

其中任一block返回一個值 - 或它不適用於類似void的行爲。

換句話說,一個拉姆達parameters -> expression相當於parameters -> { return expression; }如果expression具有非空隙型或parameters -> { expression; }如果expression具有空隙的類型(如System.out.printf())。

你的第一個版本主要使用表達式有一些開銷:

i -> i = i * 2可以降低到i -> i * 2,爲i =分配僅僅是不必要的,因爲i隨即消失,並且不使用任何進一步。

它就像

Integer function(Integer i) { 
    i = i * 2; 
    return i; 
} 

Integer function(Integer i) { 
    return (i = i * 2); 
} 

這可以簡化爲

Integer function(Integer i) { 
    return i * 2; 
} 

所有這些例子將匹配接口UnaryOperator<Integer>其是用於Function<Integer, Integer>一種特殊情況。

相反,你第二個例子是像

XY function(int i) { 
    i = i * 2; 
} 

不工作:

  • 要麼XYvoid(這將使一個Consumer<Integer>不與.map()適合)
  • XY確實是Integer(然後返回語句丟失)。

這個值的需求在哪裏(編譯代碼除外)?

好,.forEach(System.out::println);需要一個值...

所以,一切都可以被轉換成Function<T, R>可以給一個T流的.map(),導致R流:

Stream.of(1, 2, 3).map(i -> i * 2) 
Stream.of(1, 2, 3).map(i -> { return i * 2; }) 

把你給IntegerInteger,再給你Stream<Integer>。你注意到他們是裝盒的?

其他方式將

// turn a Stream<Integer> to an IntStream with a 
// int applyAsInt(Integer i) aka ToIntFunction<Integer> 
Stream.of(1, 2, 3).mapToInt(i -> i * 2) 
Stream.of(1, 2, 3).mapToInt(i -> { return i * 2; }) 

// turn an IntStream to a different IntStream with a 
// int applyAsInt(int i) aka IntUnaryOperator 
IntStream.of(1, 2, 3).map(i -> i * 2) 
IntStream.of(1, 2, 3).map(i -> { return i * 2; }) 

// turn an IntStream to a Stream<Integer> with a 
// Integer apply(int i) aka IntFunction<Integer> 
IntStream.of(1, 2, 3).mapToObj(i -> i * 2) 
IntStream.of(1, 2, 3).mapToObj(i -> { return i * 2; }) 

所有這些例子的共同點是,他們得到的值,併產生相同或不同類型的值。 (注意這些實施例是如何使用自動裝箱和AutoUnboxing根據需要)

OTOH,一切都可以被轉換成Consumer<T>可以給予一個T流的.map(),其可以是任何形式的λ的其產生的void表達:

.forEach(x -> System.out.println(x)) 
.forEach(x -> { System.out.println(x); }) // no return as you cannot return a void expression 
.forEach(System.out::println) // shorter syntax for the same thing 
.forEach(x -> { }) // just swallow the value 

考慮到這一點,很容易地看到,void表達型的λ不能被給予.map(),和具有非void類型的λ不能被給予forEach()

+3

那麼,即使沒有終端'.forEach(系統。out :: println),'map(...)'需要一個* Function *的事實足以要求lambda表達式返回一個值... – Holger

+0

我編輯了我的問題,所以你可能想編輯你的答案也是:) –

+0

@BenWin我試圖說明這一點,並希望在這方面取得成功...... – glglgl