流简介
Stream的优点:
声明性,可复合,可并行。这三个特性使得stream操作更简洁,更灵活,更高效。
Stream的特性:
1 Stream流不是一种数据结构,不保存数据,它只是在原数据集上定义了一组操作。
2. 这些操作是惰性的,即每当访问到流中的一个元素,才会在此元素上执行这一系列操作。
3. Stream不保存数据,故每个Stream流只能使用一次。
Stream的操作有两个特点:
可以多个操作链接起来运行,内部迭代。
集合和流的区别:
集合包含目前的所有元素,你要什么就去集合里取。流是你要什么,然后去计算得到你需要的值。流是按照需求生成的。
注意:
1、Stream不会自己存储数据。
2、Stream不会改变原对象,他们会返回一个新的Stream。
3、Stream操作是延迟的,他们会等到需要的结果时才执行。
4、使用并行流并不一定会提高效率,因为jvm对数据进行切片和切换线程也是需要时间的。
使用流
1.筛选
1.1 filter()方法:
该方法会接受一个谓词作为参数,并返回一个包含所有符合谓词元素的流。
public List<String> test() {
List<String> ids = Arrays.asList("1", "2", "3");
return ids.stream()
.filter(p -> p.equals("2"))
.collect(Collectors.toList());
}
根据条件查询,结果返回为[2]的ids。
1.2 distinct()方法:
该方法会筛选去除相同、重复的元素。
public List<String> test() {
List<String> ids = Arrays.asList("1", "2","2", "3");
return ids.stream()
.distinct()
.collect(Collectors.toList());
}
distinct()方法进行去重,最终返回的ids中元素为[1,2,3]。
1.3 limit()方法:
限定返回流的长度,该方法会返回一个不超过限定长度的流。
public List<String> test() {
List<String> ids = Arrays.asList("1", "2", "3");
return ids.stream()
.limit(2)
.collect(Collectors.toList());
}
使用limit(2)方法最终只会返回前2个元素,即最终返回的ids为[1,2]
1.4 skip()方法:
该方法skip(n)会跳过流的前n个元素。
public List<String> test() {
List<String> ids = Arrays.asList("1", "2", "3");
return ids.stream()
.skip(2)
.collect(Collectors.toList());
}
使用skip(2)会跳过前2个元素,从第3个元素开始返回,最终返回的ids为[3]。
2.映射
map()方法:
它会接受一个函数作为参数,这个函数会被应用到每个元素上.并将其映射成一个新的元素。
public List<Integer> test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.map(String::length)
.collect(Collectors.toList());
}
在map()方法中计算每个字符串的长度,并组成一个List集,最终返回的结果为[7,7,6]。
3.匹配
3.1.anyMatch()方法:
检验是否至少匹配一个元素。
public boolean test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.anyMatch(p->p.equals("release"));
}
使用anyMatch()返回值类型为boolean,因words中含有一个release,故最终返回值为true。
3.2 allMatch()方法:
检验是否匹配全部元素。
public boolean test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.allMatch(p -> p.length() > 5);
}
allMatch()方法返回值为boolean类型,因为words中所有字符串长度均大于5,故最终返回值为true,若5变为6则返回值为false,因为master长度不大于6。
3.3 noneMatch()方法:
检验是否匹配元素一个都没有。
public boolean test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.noneMatch(p -> p.length() > 7);
}
noneMatch()方法返回值为boolean类型,因words中所有字符串长度均小于或等于7,故最终返回值为true,若>变为>=则返回false因为存在长度等于7的字符串。
4.查找
4.1 findAny()方法:
检验是否查询到元素。
public Object test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.findAny();
}
findAny()方法 返回一个 Optional 类型的值,因words中存在值,故最终会返回其中一个值,一般为第一个值,即Optional[develop]。
4.2 findFirst()方法:
查找第一个元素。
public Object test() {
List<String> words = Arrays.asList("develop", "release", "master");
return words.stream()
.findFirst();
}
findFirst()方法 返回一个 Optional 类型的值,因wirds中存在值,故最终会返回第一个值,即Optional[develop]。工作方式类似于findAny()。
为什么会同时有 findFirst()和 findAny()呢?答案是并行。找到第一个元素,在并行上限制更多。如果你不关心返回的元素是哪个,请使用 findAny(),因为它在使用并行流时限制较少。
5.元素求值
reduce()方法:
public Integer test() {
List<Integer> words = Arrays.asList(1, 2, 3, 4, 5);
return words.stream()
.reduce(1, (a, b) -> a + b);
}
为带初始值(1)的累加,返回值类型为Integer,最终返回结果为16.
具体运算方式取决于后面的lambda表达式,该操作为初始值依次对集合中元素进行相应的运算。
public Object test() {
List<Integer> words = Arrays.asList(1, 2, 3, 4, 5);
return words.stream()
.reduce(Integer::sum);
}
为不带初始值的累加,返回一个 Optional 类型的值。最终返回结果为Optional[15]。
考虑到流中没有值的情况,reduce操作便无法返回其和,因为没有初始值.这就是为什么结果被包裹在一个Optional对象里,以表明结果可能不存在。
public Object test() {
List<Integer> words = Arrays.asList(1, 2, 3, 4, 5);
return words.stream()
.reduce(Integer::min);
}
为不带初始值的求List中的最小值,返回一个 Optional 类型的值。最终返回结果为Optional[1]。
public Object test() {
List<Integer> words = Arrays.asList(1, 2, 3, 4, 5);
return words.stream()
.reduce(Integer::max);
}
为不带初始值的求List中的最大值,返回一个 Optional 类型的值。最终返回结果为Optional[5]。