1.1概述
说到Strem便容易想到I/O Strem,而实际上,谁规定“流”就一定是流呢?在Java8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。
1.2传统集合遍历的弊端
需求:筛选出姓张且名字长度为3的人的名字并打印
List <String> list = new ArryList<> ();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
List<String> list1 = new ArryList<>();
//筛选姓张的的人名
for (String name : list1) {
if (name.startsWith("张")) {
list1.add(name);
}
}
List<String> list2 = new ArrayList<>();
// 筛选长度为3的人名
for (String name : list1) {
if (3 == name.length()) {
list2.add(name);
}
}
System.out.println(list2);
通过以上代码发现,传统的for循环不仅要专注做什么,还要专注怎么做,Java 8的Lambda让我们可 以更加专注于做什么(What),而不是怎么做(How)
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
list.stream()
.filter((name)‐>name.startsWith("张"))
.filter((name)‐>3 == name.length())
.forEach((name)‐>System.out.println(name));
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为 3、逐一打印。代码 中并没有体现使用线性循环或是其他任何算法进行遍历,我们真正要做的事情是内容被更好地体现在代码中
2.流式思想
2.1概述
整体来看,流式思想类似于工厂车间的“生产流水线”。Stream(流)是一个来自数据源的元 素队列 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计 算。 数据源 流的来源。 可以是集合,数组等。 备注:“Stream流”其实是一个集合元素的函 数模型,它并不是集合,也不是数据结构,其本身并不存储任何 元素(或其地址值)。
2.2流的获取
java.util.stream.Stream 是Java 8新加入的常用的流接口。(这并不是一个函数式接口。)
获取一个流非常简单,有以下两种常用的方式:
所有的 Collection 集合都可以通过 stream 默认方法获取流;
Stream 接口的静态方法 of 可以获取数组对应的流
2.3
,获取Collection对应的流
2.4获取Map对应流
将map拆分成键集合和值集合,再分别获取对应的流
2.5获取数组对应的流
3.Strem常用方法
3.1,概述 流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终 结方法外,其余方 法均为延迟方法。)
终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 String
3.2逐一处理:forEach
//语法
void forEach(Consumer<? super T> action);
//基本使用
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
list.stream().forEach(name ‐> System.out.println(name));
3.3过滤filter
//语法
Stream<T> filter(Predicate<? super T> predicate);
//基本使用
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
list.stream().filter((name)‐>name.startsWith("张"));
3.4统计个数:count
//语法
long count();
//基本使用
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
long count = list.stream().filter((name)‐>name.startsWith("张")).count(); System.out.println(count);
3.5取前几个;limit
limit 方法可以对流进行截取,只取用前n个。 参数是一个long型,如果集合当前长度大于参数 则进行截取;否则不进行操作
//语法
Stream<T> limit(long maxSize);
//基本使用
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
long count = list.stream().limit(2).count(); System.out.println(count);
3.6跳过几个;skip
如果希望跳过前几个元素,可以使用 skip. 方法获取一个截取之后的新流. 如果流的当前长度大于 n,则跳过前n个;否则将会得到一个长度为0的空流
//语法
Stream<T> skip(long n);
//基本使用
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("老邱");
list.add("张三丰");
long count = list.stream().skip(2).count();
3.7组合;hconcat
如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat
Stream<String> s1 = Stream.of("老邱");
Stream<String> s2 = Stream.of("小邱"); S
tream<String> s3 = Stream.concat(s1, s2); s3.forEach((name)‐>System.out.println(name));
4Stream的综合案例
需求
a. 第一个队伍只要名字为3个字的成员姓名;
b. 第一个队伍筛选之后只要前3个人;
c. 第二个队伍只要姓张的成员姓名;
d. 第二个队伍筛选之后不要前2个人;
e. 将两个队伍合并为一个队伍;
f. 打印整个队伍的Person对象信息
Stream.concat(
list.stream()
.filter((person)‐>person.getName().length() == 3) .limit(3),
list.stream()
.filter((person)‐>person.getName().startsWith("张")) .skip(2)
)
.forEach((person)‐>System.out.println(person.getName());