从lambda表达式中的方法返回值

Rog*_*gue 19 java lambda java-8

我试图弄清楚如何从lambda表达式返回一个方法值:

public int findMissingNumber(Collection<Integer> ints) {
    Single<Integer> start = new Single<>(1);
    ints.stream().mapToInt(Integer::valueOf).parallel().forEach(i -> {
        if (i != start.setValue(start.getValue() + 1)) {
            //return here
        }
    });
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

但是,似乎return在lambda表达式中使用关键字将显式返回lambda函数本身.有没有某种方法可以打破或强制整个方法返回?

Jon*_*eet 20

有没有某种方法可以打破或强制整个方法返回?

不,至少,除非你抛出异常.

基本上,这不是什么forEach意思.你可以编写一个接受一个函数的方法,该函数将返回null"keep going"而非null则为"stop,并使其成为结果"......但该方法不是 forEach.

你正在使用lambda表达式的事实在这里是偶然的.想象一下,你只是在调用forEach并传入一些参数 - 如果该调用使你的方法返回(没有异常),而没有方法本身具有return语句,那不是奇怪吗?findMissingNumberfindMissingNumber

  • @Rogue:好吧,`filter(...).findFirst()`*在第一次发现的事件时停止了...... (5认同)
  • @Rogue:嗯,你很可能用`filter()`和`findFirst()`构建它 - 让你的`filter`谓词只返回"匹配"的项,然后找到该流的第一个元素.另一方面,你的lambda表达式目前有副作用(`start.setValue()`),这不是并行化的良好起点...... (4认同)
  • 有关使用`filter`和`findFirst`的示例以及其他一些讨论,请参阅[我的回答](http://stackoverflow.com/a/24719306/1441122). (3认同)

Stu*_*rks 12

(这是XY问题的一个实例吗?)

问题是关于如何从一个lambda中返回forEach.Jon Skeet提供了一些有用的信息findFirst,同时也警告了lambda并行运行中的副作用 - 两个优点.

但对于最初的问题,我仍然在想:你想解决什么问题?

findMissingNumber示例中的方法名称是暗示性的.该方法将一组数字作为参数,并在递增计数器时对其进行迭代.它在找到不匹配时返回,或者如果没有不匹配则返回-1.由于计数器在ints处理集合中的每个值时递增一次,看起来该集合应该是有序的,除非缺少数字.

如果是这样,参数应该是a List而不是a Collection.(在这里做一个很大的假设.)在这个假设下,可以使用lambdas将代码重写为如下所示的流:

static OptionalInt findMissingNumber(List<Integer> ints) {
    return
        IntStream.rangeClosed(1, ints.size())
            .filter(i -> i != ints.get(i-1))
            .findFirst();
}
Run Code Online (Sandbox Code Playgroud)

我们使用IntStream.range生成预期在列表中的值而不是递增计数器.然后,我们依赖于对列表的随机访问,以获得列表中get预期位置的值.我们过滤不匹配并返回第一个,如果有的话.这可以避免突变,因此应该并行正确运行.(请注意,如果列表不是随机访问,则不会很好地并行化.)

如果没有找到不匹配OptionalInt,则返回值为.这比使用像标识-1"未找到"条件的标记值更明确.