2015-04-17 71 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