Java 8流式处理中的"ifPresent"

14

我正在学习有关数据流的知识,但遇到了一个问题: 我想获取列表中的最小值并将其赋值给一个整数变量。 为此,我进行了以下操作:

List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    int smallest = list.stream().min(Integer::compareTo).get();
    System.out.println(smallest);

这个很好用,我得到了1作为结果。问题是IDE发出警告,表示在检查.isPresent之前调用了Optional.get方法。为解决这个问题,我使用了稍微不同的ifPresent方法并尝试了以下操作:

int smallest = list.stream().min(Integer::compareTo).ifPresent(integer -> integer);

很不幸,这并不起作用,因为我收到了警告:Bad return type in Lambda, Integer cannot be converted to void. 我的问题最后是:如何在使用ifPresent检查的情况下将最小值赋给int smallest变量?


1
你首先需要明白为什么会得到一个Optional而不是一个整数:因为流可能为空,因此可能没有最小值。然后你需要决定如果流为空时想要得到什么样的结果。一旦你知道了你想要的结果,就可以通过查看Optional的文档来选择正确的方法来获得结果。 - JB Nizet
1
ifPresent 接受一个 Consumer 作为其参数,该消费者消耗输入值并返回无。 - Ali Dehghani
提示:可以通过 List<Integer> list = Arrays.asList( 1, 2, 3 ); 简化列表的初始化和添加。 - Gerold Broser
3个回答

10

这是我会做的方式:

package lambdas;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Michael
 * Creation date 7/31/2016.
 * @link https://dev59.com/kVkT5IYBdhLWcg3wX-dp
 */
public class MinimumExample {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        int smallest = list.stream().min(Integer::compareTo).orElse(Integer.MIN_VALUE);
        System.out.println(smallest);
    }
}

如果.min方法返回一个Optional,那么.orElse方法需要返回一个Integer。.orElse会调用.get方法吗? - Stefan B
这段代码可以运行并且有效。它被你接受的答案所支持。你有什么问题吗? - duffymo

9

Stream#min 返回 Optional 类型的结果,因为流通常可能为空,所以可能没有最小值。

 Optional<Integer> minimal = list.stream().min(Integer::compareTo);

要从Optional中获取值,您需要设置一些备用值。
Integer absent = Integer.MIN_VALUE;

最简单的方法是使用 orElse
Integer smallest = minimal.orElse(absent);

稍微长一点的可能是 isPresent
Integer smallest = minimal.isPresent() ? minimal.get() : absent;

所以orElse方法返回的是一个整数类型,而不是像min方法一样返回Optional? - Stefan B
1
是的,在这个例子中它将是 Integer。通常 Optional<T> 可以包含任何类型 T 的值,因此 orElse 返回该类型 T - Nazarii Bardiuk
非常感谢! - Stefan B
4
一个次要的注释:通常,计算最小值时的“未出现”值为Integer.MAX_VALUE,计算最大值时的“未出现”值为Integer.MIN_VALUE - Marco13
@Marco13 为什么? - Eth
1
@Eth 的意图是返回一个指示特殊情况的值。(顺便说一句:它还允许简单的实现,如 int result=MAX_VALUE;for(i:a) result=min(result,i); return result;)。当然,对于 Integer,可以对此进行争论:MIN_VALUEMAX_VALUE 都可以是合法的结果。但是在计算最小值时,返回最大数表明根本没有找到任何值。(这甚至对于 DoublePOSITIVE_INFINITY 更有意义)。许多库都以类似的方式完成,可以称之为“最佳实践”,或者至少可以合理地满足期望。 - Marco13

3
ifPresent方法以Consumer<? super T>作为参数。简单地说,它应该是一个没有return语句的操作。如果值存在,您可以将其打印出来。
[...].ifPresent(System.out::print);

但这并不是IDEA所说的。我认为,你只需要保存一个Option<Integer>实例,然后通过isPresent检查它即可:

Optional<Integer> o = list.stream().min(Integer::compareTo);
if (o.isPresent()) {
    smallest = o.get();
}

当然,使用 orElse 还有更方便的方式:
smallest = o.orElse(Integer.MIN_VALUE);

或者使用三元运算符:

smallest = o.isPresent() ? o.get() : Integer.MIN_VALUE;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接