繁体   English   中英

来自 Lambda 表达式的有效 void 返回语句(示例:可运行)

[英]Valid void Return Statements from Lambda Expressions (Example: Runnable)

在 Java 中看到一些关于具有void返回类型的功能接口的奇怪行为。

有人可以解释为什么下面的task5task6的声明可以编译吗?

public class Test {

    private static int counter;

    private static void testRunnable() {
        /* Runnable has a void return type so the following won't compile.
        * Error message is Void methods cannot return a value. (Java 67108969) Makes sense... */
        // Runnable task1 = () -> { return counter; };
        // Runnable task2 = () -> { return counter + 1; };
        // Runnable task3 = () -> counter;
        // Runnable task4 = () -> counter + 1;

        /* But for some reason, this is totally acceptable. Why? */
        Runnable task5 = () -> counter++;
        Runnable task6 = () -> ++counter;
    }
}

lambda 表达式() -> counter++; 作为counter++; 是一个语句表达式。 这是在JLS中明确允许的:

如果 function 类型的结果为 void,则 lambda 主体是语句表达式 (§14.8) 或 void 兼容块。

对于语句表达式的定义

表达式语句通过对表达式求值来执行; 如果表达式有值,则丢弃该值。

如果您阅读了整个 JLS 15.27.3,您就会明白为什么() -> {return counter + 1;}不兼容 void。 lambda 正文未使用与简单表达式语句完全相同的规则进行验证。

换句话说, counter++; ++counter; 是语句表达式,这意味着表达式可以被评估并被视为一个语句,其结果被简单地丢弃。

转换为块体时会更清晰(或者看起来更熟悉):

Runnable task5 = () -> {
    counter++; //result discarded, but you can't use "return counter++;"
};
Runnable task6 = () -> {
    ++counter; //result discarded, but you can't use "return ++counter;"
};

这与UnaryOperator ,至少就该功能接口而言。 碰巧counter++IntUnaryOperator兼容,但表达式可能是其他任何内容,包括(但不限于)以下内容,并且您的问题仍然适用,因为该语句会产生结果:

Runnable task5 = () -> counter += 1;
Runnable task6 = () -> counter = counter + 1;
Runnable task7 = () -> Math.addExact(counter, 1); // no change in counter
Runnable task8 = () -> return2(); //return2 takes no input

所有这些都是与Runnable.run()一致的产生 int 的表达式。 具体来说, task8不接受输入但会产生结果; 它甚至不兼容任何一元运算符功能接口。

/* 但出于某种原因,这是完全可以接受的。 为什么? */ 可运行 task5 = () -> counter++; 可运行任务6 = () -> ++counter;

因为这两个任务都返回无效。 counter++; ++counter是结果将被丢弃的操作。 此外,它们都不会被编译器解释为return counter++; return ++counter; .

由于明显的原因,任务 1 和任务 2 不起作用,无论是 return 还是 int:

 Runnable task1 = () -> { return counter; };
 Runnable task2 = () -> { return counter + 1;};

任务 3 和任务 4 虽然没有显式返回和 int,但都隐式返回一个 int:

Runnable task3 = () -> counter;
Runnable task4 = () -> counter + 1;

任务 1 和任务在语义上与任务 3 和任务 4 相同,只是语法糖。

在任务1和任务2中, () -> { return counter; }; () -> { return counter; }; () -> { return counter + 1;}; 语句 lambda可以替换为表达式 lambda () -> counter; () -> counter + 1; , 分别

使用这两个功能接口来理解概念的示例:

Exp: 1. interface having method with void return type

interface InterfaceNameOne{
    void methodOne();  // method has void return type
}

InterfaceNameOne ref1 = () -> statement1;  // here should not be a return statement

Exp: 2. interface having method with any return type here int as example

interface InterfaceNameTwo{
    int methodTwo(int x);  // method has return type
}

InterfaceNameTwo ref2 = (x) -> {return statement;};  // here should be a return statement
InterfaceNameTwo ref3 = (x) -> statement;  // it is also a return statement

虽然Runnable 是像第一个 (1) 示例一样的功能接口,但这就是为什么不能有像这样的 return 语句

Runnable ref4 = () -> counter=counter+1; // equivalent to counter++ & ++counter without return statement

But not like

Runnable ref5 = () -> counter; // equivalent to return statement
Runnable ref6 = () -> {return counter;}; // equivalent to return statement

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM