0%

stream and lambda(20) - if/else 的处理

在 Stream 的处理过程中,我们有时会遇到写 if/else 的情况,而带有 if/else 的逻辑通常会有些长。在写 lambda 表达式时,我们又需要尽量写简洁的语句。那么,对于含有判断语句的情况,该怎么处理?

针对 if/else 通常有以下几种场景:

  1. if
  2. if else
  3. if else if else if else
  4. 嵌套 if/else

简单 if/else

filter 处理

使用 filter 可以过滤数据,再对过滤出来的数据做处理。过滤时传入的判断条件,对应的正是 if

1
2
3
4
5
public void ifFilterDemo() {
List<String> names = Arrays.asList("zhangs", "lis", "wangw", "zhaol");
List<String> newNames = names.stream().filter(s -> s.contains("s")).collect(Collectors.toList());
System.out.println(newNames);
}

*Match 处理

比如有一个集合,我们循环遍历判断,如果某一条符合条件,直接 return,否则会处理我们自己的逻辑。

1
2
3
4
5
6
7
8
public boolean hasElement(List<String> list, String element) {
for (String patt : list) {
if(MathUtil.match(patt, element)) {
return true;
}
}
return false;
}

这里,其实我们可以简单的用以下语句完成。

1
return list.parallelStream().anyMatch(pat -> SaFoxUtil.vagueMatch(pat, element));

findAny/findFirst 处理

*Match 方法可以简单的处理布尔类型,如果是返回特定值的话,可以借助 findAny/findFirst

1
2
3
4
5
6
7
8
public Token getToken(List<Token> tokenList, String tokenValue) {
for (Token token : tokenList) {
if (token.getValue().equals(tokenValue)) {
return token;
}
}
return null;
}

以上逻辑也可以使用以下语句简单完成。

1
2
3
4
5
public Token getToken(List<Token> tokenList, String tokenValue) {
return tokenList.stream()
.filter(t -> t.getValue().equals(tokenValue))
.findFirst().orElse(null);
}

参考 Optional 的另一种思路

上面的例子中,我们使用到了 Optional 来处理简单的 if/else。其实参考这种思想,我们也可以写一个容器类,将 if/else 包装成方法,同时传入一个 Consumer 来执行对应的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class IfElseCondition<T> {

private final T value;
/**
* 判断是否有条件命中,如果无命中,otherwise 兜底方法才会执行。
*/
private boolean hit = false;

private IfElseCondition(T value) {
this.value = Objects.requireNonNull(value);
}

/**
* 提供静态方法便于生成对象
* @param item 需要判断的对象
*/
public static <T> IfElseCondition<T> of(T item) {
return new IfElseCondition<>(item);
}

public IfElseCondition<T> ifTrue(Predicate<T> predicate, Consumer<T> ifConsumer) {
if (predicate.test(value)) {
hit = true;
ifConsumer.accept(value);
}
return this;
}

public IfElseCondition<T> elsif(Predicate<T> predicate, Consumer<T> ifConsumer) {
if (!hit && predicate.test(value)) {
hit = true;
ifConsumer.accept(value);
}
return this;
}

public void otherwise(Consumer<T> elseConsumer) {
if (!hit) {
elseConsumer.accept(value);
}
}

public void ifOrOtherwise(Predicate<T> predicate, Consumer<T> ifConsumer, Consumer<T> elseConsumer) {
if (predicate.test(value)) {
ifConsumer.accept(value);
} else {
elseConsumer.accept(value);
}
}

public T getValue() {
return value;
}
}

来使用一下:

1
2
3
4
5
6
7
8
public void ifElseifElseDemo() {
List<String> names = Arrays.asList("zhangs", "lis", "wangw", "zhaol");
names.stream().map(IfElseCondition::of).forEach(
e ->
e.ifTrue(s -> s.contains("s"), s -> System.out.println(s + " contains s"))
.elsif(s -> s.length() > 5, s -> System.out.println(s + ".length > 5"))
.otherwise(s -> System.out.println(s + " not contains s")));
}

程序正常输出:

zhangs contains s
lis contains s
wangwu.length > 5
zhaol not contains s

复杂的逻辑判断

这种情况,真的不建议再用 lambda 来写了。大多数情况下,if/else 真的是很好用的。

总结

  • 简单逻辑可以使用 filter, anyMatch, allMatch, noneMatch, partitioningBy 之类的方法来代替。
  • 复杂逻辑不建议使用 lambda 来写,单独抽离出一个方法也许更好,不要太执着。
  • if/else 大多数情况下直接使用是没问题的。
  • 可以效仿 Optional 写一个容器工具类来包装 if/else 方法。