是否不鼓励在 java 流中使用 if ?

Is it discouraged to use if in java streams?

考虑以下问题:我应该关掉房间里所有的灯。房间包含在一套房间里。是否不鼓励使用 forEach 和 if? (我读了我所有的讲义,他们都没有提到 .forEach(p -> {if... construct.. 但是我发现它是最简单的。如果不鼓励,我该如何解决问题?为什么不鼓励?

public void turnOffLampsInRooms(Set<Room> rooms) {
    lamps.stream()
    .forEach(p -> {if (p.getRoom() != null && rooms.contains(p.getRoom())) {
        p.turnOff();
    }   
    });
}

不使用 if,而是使用以下条件进行过滤:

set.stream()
.filter(p -> p.getRoom() != null)
.filter(p -> rooms.contains(p.getRoom()))
.forEach(SmartLamp::turnOff);

注意方法参考 SmartLamp::turnOff 的使用,它通常优于等效的 lambda p -> p.turnOff().

事实是,您使用优化良好的 Stream API,条件稍慢 if。它的语法是正确的,它可以正常工作,但它看起来不太好,而且对于大量数据来说速度较慢。

首先,您应该将 if 语句移动到 .filter 流调用:

public void turnOffLampsInRooms(Set<Room> rooms) {
    Set<SmartLamp> set = new HashSet<>(lamps);
    set.stream()
            .filter(p -> p.getRoom() != null && rooms.contains(p.getRoom()))
            .forEach(p -> p.turnOff()); // conditions checked already
}

接下来,.filter可以拆分成单独的:

public void turnOffLampsInRooms(Set<Room> rooms) {
    Set<SmartLamp> set = new HashSet<>(lamps);
    set.stream()
            .filter(p -> p.getRoom() != null)
            .filter(p -> rooms.contains(p.getRoom())) // the same meaning
            .forEach(p -> p.turnOff());
}

最后更改对方法引用的调用:

public void turnOffLampsInRooms(Set<Room> rooms) {
    Set<SmartLamp> set = new HashSet<>(lamps);
    set.stream()
            .filter(p -> p.getRoom() != null)
            .filter(p -> rooms.contains(p.getRoom()))
            .forEach(SmartLamp::turnOff); // method reference
}

主要优点是流优化,但也更容易逐步阅读流的作用。