有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在单个lambda表达式中向不同集合添加元素

我可能使用了错误的术语,请随意更正

我有一个测试方法,它需要Runnable

void expectRollback(Runnable r) { .. }

我可以这样称呼这个方法:

expectRollback(() -> aList.add(x))

酷,我理解兰巴斯!这太棒了。让我们超级聪明

expectRollback(() -> aList.add(x) && bList.add(y))

但是什么?这不会编译:'void' methods cannot return a value.但是第一个调用不也会返回一个值吗?第一次和第二次通话的区别是什么


共 (2) 个答案

  1. # 1 楼答案

    基本上,第一个表达式是调用方法的方式,但忽略结果:

     aList.add(x) // actually returns a boolean but you ignore this result
    

    事实上,这对lambdas来说并不是什么新鲜事,因为自java出现以来一直是这样的:

    List<Integer> list ...
    list.add(1); // returns boolean but we ignore the result almost always
    

    那么,为什么在第二个例子中不忽略结果呢?因为JLS是这样说的,正如here。但有4种类型可以工作:

    Method Invocations
    Assignments
    Increment and Decrement expressions
    Class Instance Creation expressions
    

    上一个示例使用的&&不是JLS中描述的4种类型中的任何一种,因此是编译时错误

    您可以创建一个helper方法来添加到这两个列表中(或者像您对Boolean.valueOf所做的那样):

    public static boolean helper(int x) {
        boolean result = first.add(x) && second.add(x);
        return result;
    }
    

    并使用它:

    expectRollback(() -> helper(x))
    
  2. # 2 楼答案

    这很微妙,但我想我明白了

    JLS 15.27.3我们有:

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

    • ...
    • If the lambda parameters are assumed to have the same types as the function type's parameter types, then:
      • If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.
      • ...
    • ...

    现在aList.add(x)是一个语句表达式,但aList.add(x) && bList.add(y)不是。你可以看到,在没有任何lambda参与的情况下,只需尝试将它们用作语句:

    aList.add(x); // Fine
    aList.add(x) && bList.add(y); // Error: "not a statement"
    

    如果将该表达式包装在方法调用中,则没有问题,因为该方法调用也是一个语句表达式:

    rollback(() -> Boolean.valueOf(aList.add(x) && bList.add(y)));
    

    我并不是真的建议你这么做——只是想解释一下为什么这样做会奏效,但你之前的尝试没有奏效

    如果我们假设List.add真的会像文档记录的那样每次返回true,只需使用块lambda:

    rollback(() -> { aList.add(x); bList.add(y); });
    

    我认为这更清楚,因为它更明显地表明,您不关心第一个add调用返回的值