如何使用流有条件地终止循环收集

Sha*_*ain 4 java java-8 java-stream

如何使用流来实现以下代码片段显示的内容?基本上,我需要根据条件终止循环返回一个值,或者根据条件再次返回另一个值.

enum Day {
  SUNDAY, MONDAY, TUESDAY, WEDNESDAY
} 

class MyObj {
  Day d;
  public Day getDay();
}

List<MyObj> myObjList;

Day Myfunc () {
// If atleast one obj belongs to SUNDAY or MONDAY, return.
Day myDay = null;
for(MyObj myObj : myObjList) {
  if(myObj.getDay() == Day.SUNDAY || myObj.getDay() == Day.MONDAY) {
    return myObj.getDay();
  }
  else if (myObj.getDay() == Day.TUESDAY) {
    myDay = myObj.getDay();
  }
 }
return myDay;
}
Run Code Online (Sandbox Code Playgroud)

Tag*_*eev 5

我理解你的函数的逻辑如下:

  1. 如果输入中有SUNDAY或MONDAY,则返回其中的第一个.
  2. 否则,如果有星期二,请将其退回.
  3. 否则返回null.

您可以在Java-8样式中实现此逻辑,迭代列表两次并使用Optional.orElseGet:

myObjList.stream().map(MyObj::getDay).filter(d -> d == Day.SUNDAY || d == Day.MONDAY)
    .findFirst()
    .orElseGet(() -> myObjList
        .stream().map(MyObj::getDay).anyMatch(d -> d == Day.TUESDAY) ? Day.TUESDAY : null);
Run Code Online (Sandbox Code Playgroud)

看起来有点难看,所以最好坚持原始的命令式代码.


另一种一次性解决方案是引入日期优先级并使用它:

int priority(Day d) {
    switch(d) {
    case SUNDAY:
    case MONDAY:
        return 10; // max priority
    case TUESDAY:
        return 5;
    default:
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以使用Stream.max:

return myObjList.stream().map(MyObj::getDay).max(Comparator.comparingInt(this::priority))
        .filter(day -> priority(day) > 0).orElse(null);
Run Code Online (Sandbox Code Playgroud)

虽然它比原始代码更长,但这种解决方案看起来更灵活:您可以轻松添加更多调整priority方法的案例.

  • @singhakash,代码不返回原始列表元素(`MyObj`类型),而是返回`Day`枚举值.再看一遍. (2认同)