[Java][StreamAPI]关于allMatch()方法
流媒体的陷阱
Java8的Stream是非常方便的,但需要注意它只提供一个”流”的功能。其中的allMatch非常危险!如果不小心使用它,将会产生副作用。因为allMatch会进行短路评估(如果存在不满足判定条件的元素,就会停止后续的处理而直接结束)。
考试内容
创建一个保存字符串的类,并对保存它们的列表进行判断,判断所有字符串的长度是否都小于等于5个字符,如果列表中包含长度超过6个字符的数据,则将该字符串替换为”sorry”。使用以下四种处理方法进行测试。
-
- A. Listに対して直接allMatchを実行
-
- B. mapしてからStream処理内でallMatchを実行
-
- C: mapをして一度Listに保存してから新たにStreamをひらいてallMatchを実行
- D: 処理結果をfilterしてその数とStreamを流している対象のリスト長とを比較する
样本代码。我认为很简单。
public class MyProject {
public static void main(String[] args) {
List<String> baseStrList = Arrays.asList("test", "tetetete", "tetetete", "tetetete", "tetetete");
List<TestData> listA = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
List<TestData> listB = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
List<TestData> listC = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
List<TestData> listD = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
boolean a = listA.stream().allMatch(TestData::checkLength);
boolean b = listB.stream().map(TestData::checkLength).allMatch(e -> e);
List<Boolean> list3Temp = listC.stream().map(TestData::checkLength).collect(Collectors.toList());
boolean c = list3Temp.stream().allMatch(e -> e);
boolean d = listD.size() == listD.stream().filter(TestData::checkLength).count();
System.out.println("a:" + a + ", list:" + listA.toString());
System.out.println("b:" + b + ", list:" + listB.toString());
System.out.println("c:" + c + ", list:" + listC.toString());
System.out.println("d:" + d + ", list:" + listD.toString());
}
public static class TestData {
public String content = "fefe";
@Override
public String toString() {
return content;
}
public TestData(String a) {
this.content = a;
}
public boolean checkLength() {
if (getContent().length() > 5) {
setContent("sorry");
return false;
}
return true;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
}
结果:
a:false, list:[test, sorry, tetetete, tetetete, tetetete]
b:false, list:[test, sorry, tetetete, tetetete, tetetete]
c:false, list:[test, sorry, sorry, sorry, sorry]
d:false, list:[test, sorry, sorry, sorry, sorry]
考察結果 chá jié guǒ)
-
- A: allMatchの短絡評価によって、2要素目のみsorryが代入されて、そのあとの要素は処理されないまま。
-
- B: StreamAPIのmap()を挟んだとしてもallMatch()の手中にいるため、残念ながらAと同じ結果になる
-
- C: 一度新規にListを生成しているため、効率は悪いが全要素に対して正しく処理が行われている
- D: こちらは新規にListを生成していないのでcよりも効率がいいはず。。。
从上述可以知道,我们需要理解allMatch函数的正确使用方法。
从个人角度来看,我认为只有在需要对列表进行某种确认时才需要使用allMatch。例如,在导致数据破坏或需要执行某种特殊处理并对结果进行汇总的情况下,可能更适合采用C或D的方式。
[2017/10/23 09:40追記] 另外,当然要注意空列表的allMatch结果为true。即使使用D的方法也会得出相同的结果。
顺便提一下
因为使用Lombok可以让事情变得轻松,所以大家都来使用吧。
import lombok.Data;
import lombok.val;
import java.util.Arrays;
import java.util.stream.Collectors;
public class MyProject {
public static void main(String[] args) {
val baseStrList = Arrays.asList("test", "tetetete", "tetetete", "tetetete", "tetetete");
val listA = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
val listB = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
val listC = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
val listD = baseStrList.stream().map(TestData::new).collect(Collectors.toList());
val a = listA.stream().allMatch(TestData::checkLength);
val b = listB.stream().map(TestData::checkLength).allMatch(e -> e);
val list3Temp = listC.stream().map(TestData::checkLength).collect(Collectors.toList());
val c = list3Temp.stream().allMatch(e -> e);
val d = listD.size() == listD.stream().filter(TestData::checkLength).count();
System.out.println("a:" + a + ", list:" + listA.toString());
System.out.println("b:" + b + ", list:" + listB.toString());
System.out.println("c:" + c + ", list:" + listC.toString());
System.out.println("d:" + d + ", list:" + listD.toString());
}
@Data
public static class TestData {
public String content = "fefe";
@Override
public String toString() {
return content;
}
public TestData(String a) {
this.content = a;
}
public boolean checkLength() {
if (getContent().length() > 5) {
setContent("sorry");
return false;
}
return true;
}
}
}