使用Java 8获取列表的最后一个非null元素

Zhe*_*yaM 7 java lambda java-8 java-stream

在Java 7中,如果我想获取列表的最后一个非null元素,我写这样的东西:

public CustomObject getLastObject(List<CustomObject> list) {
    for (int index = list.size() - 1; index > 0; index--) {
        if (list.get(index) != null) {
            return list.get(index);
        }
    }
    // handling of case when all elements are null
    // or list is empty
    ...
}
Run Code Online (Sandbox Code Playgroud)

我想通过使用lambdas或Java 8的另一个特性来编写更短的代码.例如,如果我想获得第一个非null元素,我可以这样写:

public void someMethod(List<CustomObject> list) {
    .....
    CustomObject object = getFirstObject(list).orElseGet(/*handle this case*/);
    .....
}

public Optional<CustomObject> getFirstObject(List<CustomObject> list) {
    return list.stream().filter(object -> object != null).findFirst();
}
Run Code Online (Sandbox Code Playgroud)

也许有人知道如何解决这个问题?

Tun*_*aki 11

一种可能的解决方案是以相反的顺序迭代List并保留第一个非null元素:

public Optional<CustomObject> getLastObject(List<CustomObject> list) {
    return IntStream.range(0, list.size()).mapToObj(i -> list.get(list.size() - i - 1))
                                          .filter(Objects::nonNull)
                                          .findFirst();
}
Run Code Online (Sandbox Code Playgroud)

请注意,findLastStream API中没有方法,因为Stream不一定是有序的或有限的.

另一个解决方案是迭代列表并通过仅保留当前元素来减少它.这有效地将Stream减少到最后一个元素.

public Optional<CustomObject> getLastObject(List<CustomObject> list) {
    return list.stream().filter(Objects::nonNull).reduce((a, b) -> b);
}
Run Code Online (Sandbox Code Playgroud)

  • @assylias [`Collection.stream()`](https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream--)返回的流是顺序的(每个Javadoc) (2认同)