为什么 Java 8 Stream forEach 方法的行为不同? [英] Why Java 8 Stream forEach method behaves differently?

查看:24
本文介绍了为什么 Java 8 Stream forEach 方法的行为不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据我对 java 8 lambda 表达式的理解,如果我们不在大括号中的->"之后包含代码,则该值将被隐式返回.但是在下面的例子中,forEach 方法需要 Consumer 并且表达式返回值,但编译器在 Eclipse 中没有给出错误.

As per my understanding of java 8 lambda expressions, if we don't include code after "->" in curly braces that value will be returned implicitly. But in case of below example, forEach method expects Consumer and expression returns value but the compiler is not giving an error in Eclipse.

List<StringBuilder> messages = Arrays.asList(new StringBuilder(), new StringBuilder());

messages.stream().forEach(s-> s.append("helloworld"));//works fine 

messages.stream().forEach((StringBuilder s)-> s.append("helloworld")); //works fine 

messages.stream().forEach(s-> s); // doesn't work , Void methods cannot return a value

messages.stream().forEach(s-> s.toString()); // works fine

messages.stream().forEach(s-> {return s.append("helloworld");}); // doesn't work , Void methods cannot return a value

messages.stream().forEach((StringBuilder s)-> {return s.append("helloworld");});  // doesn't work , Void methods cannot return a value

s.append 返回 StringBuilder 并且 s.toString() 返回 String 但 lambda 将其视为 <代码>无效.

s.append returns StringBuilder and s.toString() returns String but lambda treats it as void.

我在这里错过了什么?为什么我们在对象上调用方法时编译器不报错?

What am I missing here? Why isn't the compiler giving an error when we invoke method on object?

推荐答案

来自 JLS 15.27.3.Lambda 表达式的类型:

一个 lambda 表达式与函数类型一致,如果所有的以下是正确的:

A lambda expression is congruent with a function type if all of the following are true:

  • 函数类型没有类型参数.

  • The function type has no type parameters.

lambda 参数个数与函数类型的参数类型个数相同.

The number of lambda parameters is the same as the number of parameter types of the function type.

如果 lambda 表达式是显式类型的,则其形参类型与函数类型的形参类型相同.

If the lambda expression is explicitly typed, its formal parameter types are the same as the parameter types of the function type.

  • 如果假设 lambda 参数具有与函数类型的参数类型相同的类型,则:

  • If the lambda parameters are assumed to have the same types as the function type's parameter types, then:

如果函数类型的结果为 void,则 lambda 主体是语句表达式(第 14.8 节)或与 void 兼容的块.

如果函数类型的结果是(非空)类型 R,则 i) lambda 主体是与 R 兼容的表达式在赋值上下文中,或 ii) lambda 主体是值兼容的块,并且每个结果表达式(第 15.27.2 节)都与 R 兼容分配上下文.

If the function type's result is a (non-void) type R, then either i) the lambda body is an expression that is compatible with R in an assignment context, or ii) the lambda body is a value-compatible block, and each result expression (§15.27.2) is compatible with R in an assignment context.

上面突出显示的句子意味着任何语句 lambda 表达式(即没有块的 lambda 表达式)匹配单个方法的返回类型为 void 的函数式接口(例如 Consumercode> forEach 方法所需的功能接口).

The highlighted sentence above means that any statement lambda expression (i.e. a lambda expression without a block) matches a functional interface whose single method's return type is void (such as the Consumer functional interface required by the forEach method).

这解释了为什么 s.append("helloworld") &s.toString()(您的 1,2 & 4 示例)作为语句 lambda 表达式工作正常.

This explains why s.append("helloworld") & s.toString() (your 1,2 & 4 examples) work fine as statement lambda expressions.

示例 5 &6 不起作用,因为它们具有块 lambda 主体,它们是值兼容的 lambda 表达式.为了void-compatible,所有的return语句必须不返回任何内容(即只有return;).

examples 5 & 6 don't work, since those have block lambda bodies which are value-compatible lambda expressions. To be void-compatible, all the return statements must return nothing (i.e. just return;).

另一方面,以下 void-compatible 块 lambda 主体将通过编译:

On the other hand, the following void-compatible block lambda bodies will pass compilation :

messages.stream().forEach(s-> {s.append("helloworld");});
messages.stream().forEach(s-> {s.append("helloworld"); return;});

您的第四个示例 - messages.stream().forEach(s-> s); 不起作用,原因与以下方法无法通过编译的原因相同:

Your 4th example - messages.stream().forEach(s-> s); doesn't work for the same reason the following method doesn't pass compilation :

void method (StringBuilder s)
{
    s;
}

这篇关于为什么 Java 8 Stream forEach 方法的行为不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆