Stream流,方法引用
Stream流
代码展示
1 | public static void main(String[] args) { |
引言
就以上代码来看,如果使用传统的处理集合的方法,就需要创建两个新的集合,再对集合中的元素进行操作,最后在遍历集合输出结果,而Stream流的方式,显然更加简单优雅。
Stream是一个来自数据源的元素队列
- 元素是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
- 数据源流的来源,可以是集合,数组等。
和以前的Collection操作不同,Stream操作还有两个基础的特性:
- Pipelining:中间操作都会返回流对象本身,这样多个操作可以串联成一个管道,如同流式风格。这样做可以对操作进行优化,比如延迟执行和短路。
- 内部迭代:以前对集合遍历都是通过iterator或者增强for循环的方式,显式的在集合外部进行迭代,这叫做外部迭代。Stream提供了内部迭代的方式,流可以直接调用遍历方法。
当使用一个流的时候,通常包括三个基本步骤:获取一个数据源->数据转换->执行操作获取想要的结果。每次转换原油Stream对象不改变,返回一个新的Stream对象,这就允许其操作可以像链条一样排列,形成一个管道。
获取流
两种常用的方式:
- 所有的Collection集合都可以通过stream默认方法获取流
- stream接口的静态方法of可以获取数组对应的流
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//把集合转换为Stream流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream1 = set.stream();
//获取值,存储到一个Set集合中
Map<String,String> map = new HashMap<>();
Set<String> keySet = map.keySet();
Stream<String> stream2 = keySet.stream();
//获取值,存储到一个Collection集合中
Collection<String> values = map.values();
Stream<String> stream3 = values.stream();
//获取键值对
Set<Map.Entry<String,String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream4 = entries.stream();
//把数组转换为Stream流
Stream<Integer> stream5 = Stream.of(1, 2, 3, 4, 5, 6);
//可变参数,可以传递数组
Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream6 = Stream.of(arr);常用方法
- 延迟方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。
- 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持蕾丝Stringbuilder那样的链式调用。
除了终结方法外,其余方法均为延迟方法。本小节之外的更多方法,请自行参考API文档。
逐一处理:forEach:
- void forEach(Consumer<? super T> action);
作用:用来遍历流中的数据,是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法。
过滤:filter:
可以通过filter将一个流转换成另一个子集流。
1 | Stream<T> filter(Predicate<? super T> predicate); |
映射:map:
可以将流中的元素映射到另一个流中,可以使用map方法。
1 | Stream<String> stringStream = Stream.of("1", "2", "3", "4"); |
统计个数:count
记录元素个数,返回的是long类型
- long conut()
取用前几个:limit
1 | Stream<T> limit(long maxSize); |
跳过前几个:skip
如果跳过的个数大于长度,会返回一个长度为0的空流
1 | Stream<T> skip(long n); |
组合:concat
如果有两个流,希望合并成一个流,那么可以使用Stream接口的静态方法concat。
1 | static <T> Stream<T> concat(Stream<? extends T> a,Stream<? extends T> b) |
方法引用
在使用Lambda表达式的时候,我们实际上传递出去的代码就是一种解决方案:拿什么参数做什么操作。那么考虑一种情况,如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑?
方法引用符
双冒号::为引用运算符,而他所在的表达式被成为称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么可以通过双冒号来引用该方法作为Lambda的替代者。
1 | .forEach(System.out::println); |
方法引用的使用前提
- 通过对象引用成员方法
- 对象名是已经存在的,成员方法也是已经存在的