Stream流
1.8 java推出的新特性
- Stream流的出现,可以让我们
减少代码量
,使得代码更加的优雅
,同时会使得代码不易阅读
传统写法与Stream流的比较
使用传统的写法:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("李四");
list.add("王五");
//遍历
for(String name : list){
System.out.println(name);
}
这样会输出
使用Stream的写法:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("李四");
list.add("王五");
//遍历
list.stream().forEach(name-> System.out.println(name));
同样会输出
或许这样还不太容易看得出变得更加方便了…
提出一个新的需求
1. 对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合A中
2. 并且要求只要姓名长度为三的人,存储到一个新集合B中
3. 遍历新集合B
- 使用传统的写法:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("张三丰");
list.add("李白");
list.add("李清照");
list.add("周杰伦");
list.add("张老头");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
List<String> listA = new ArrayList<>();
for(String name : list){
if(name.startsWith("张")){
listA .add(name);
}
}
//只要姓名长度为三的人,存储到一个新集合中
List<String> listB = new ArrayList<>();
for(String name: listA){
if(name.length() == 3){
listB.add(name);
}
}
//遍历2的新集合
for(String name: listB){
System.out.println(name);
}
输出结果:
- 使用Stream的写法:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("张三丰");
list.add("李白");
list.add("李清照");
list.add("周杰伦");
list.add("张老头");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
//只要姓名长度为三的人,存储到一个新集合中
//遍历新集合
list.stream()
.filter(name->name.startsWith("张"))
.filter(name->name.length() == 3)
.forEach(name->System.out.println(name));
输出结果同样是
通过这个列子就能很好的看出Steram流的代码量少
,简洁
,同时缺点相对于传统的方法,代码变得不易阅读
如何获取Stream流
- 一. 可以通过API文档在
java.util.stream
找到它的Interface Stream<T>
接口,使用静态方法of来进行获取
Stream<String> stream1 = Stream.of("张三","李四","王五");
Stream<Integer> stream2 = Stream.of(1,2,3);
//使用数组获取Stream流
String[] str = {"张三","李四","王五"};
stream3 = Stream.of(str);
Integer[] in = {1,2,3};
stream3 = Stream.of(in);
- 二.把集合转换成Stream流
//可以改成Integer等别的类型
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
//map只能进行转换然后存取
Map<String,String> map = new HashMap<>();
//1. 换取键,存储到Set集合中
Set<String> keySet = map.keySet();
Stream<String> stream3 = keySet.stream();
//2. 获取值,存储到Collection集合中
Collection<String> values = map.values();
Stream<String> stream4 = values.stream();
//3. 获取键值对(键与值的映射关系 enterSet)
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream5 = entries.stream();
Stream流的一些常用的方法
- forEach: 遍历
Stream<T> forEach(Consumer<? super T> action)
Consumer<? super T> action 是一个抽象方法,用于消费的
由于是抽象方法所以我们可以使用lambda表达式
例子:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("李四");
list.add("王五");
//遍历
list.stream().forEach(name-> System.out.println(name));
//name-> System.out.println(name)是一个lambda表达式
结果:
- filter: 是否匹配(条件)
Stream<T> filter(Predicate<? super T> predicate)
Predicate<? super T> predicate 是一个抽象方法 返回的是一个boolean值
例子:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("李四");
list.add("张三丰");
list.add("花无缺");
//开头是否有张
//姓名是否三个字
list.stream().filter(name->name.startsWith("张"))
.filter(name->name.length() == 3)
.forEach(name->System.out.println(name));
//以下都是lambda表达式
//name->name.startsWith("张") startsWith方法是测试此字符串是否以指定的前缀开头。
//name->name.length() == 3
//name->System.out.println(name)
输出结果
- map: 转换数据类型
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Function<? super T,? extends R> mapper 是一个抽象方法,可以把参数1转换成参数2的数据类型
例子:
//获取一个String类型的Stream流
Stream<String> stream = Stream.of("1", "2", "3", "4");
//将String类型转换成Integer类型,不仅可以转换成Integer类型也可以转换成对象
Stream<Integer> stream2 = stream.map(s->Integer.parseInt(s));
//遍历stream2
stream2.forEach(in-> System.out.println(in));
//其实也可以连着写
//stream.map(s->Integer.parseInt(s)).forEach(in-> System.out.println(in));
以下都是lambda表达式
//s->Integer.parseInt(s)
//in-> System.out.println(in)
输出结果:
- count: 获取数量
例子:
//创建一个集合
List<String> list = new ArrayList<>();
//添加
list.add("张三");
list.add("李四");
list.add("张三丰");
list.add("花无缺");
//获取数量
long count = list.stream().count();
System.out.println(count);
输出结果:
- limit: 截取
例子:
String[] str = {"张三","李四","王五","赵六","田七"};
Stream<String> stream = Stream.of(str);
Stream<String> stream2 = stream.limit(3); //截取1-3的数据
stream2 .forEach(str->System.out.println(str));
结果:
- skip: 用来跳过元素
例子:
String[] str = {"张三","李四","王五","赵六","田七"};
Stream<String> stream = Stream.of(str);
Stream<String> stream2 = stream.skip(3); //跳过前3个
stream2 .forEach(name->System.out.println(name));
结果:
7. concat:
<R,A> R collect(Collector<? super T,A,R> collector)
Collector<? super T,A,R> collector
是一个抽象方法,可以将两个stream流连接起来
例子:
String[] str1 = {"张三","李四","王五","赵六","田七"};
String[] str2 = {"李白","杜甫","王安石","白居易"};
Stream<String> stream1 = Stream.of(str1);
Stream<String> stream2 = Stream.of(str2);
Stream<String> stream = Stream.concat(stream1,stream2);
stream.forEach(name->System.out.println(name));
结果:
注意:
- Stream流使用一次后,就会关闭,如果重新使用就会报错(
Stream流只能使用一次
)
例如:
String[] str = {"张三","李四","王五","赵六","田七"};
Stream<String> stream = Stream.of(str);
//使用第一次
stream.skip(1);
//使用第二次
stream.forEach(name-> System.out.println(name));
报错:IllegalStateException: stream has already been operated upon or closed