文章目录
Stream流介绍
JDK1.8的新特性之一
它跟我们所学的 IO 流完全没有什么关系
Stream 它是Lambda的衍生物。
传统方式遍历的问题
需求:我们先找出性张的,再性张的中找出三个字的,然后遍历集合
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList();
//给集合添加元素
Collections.addAll(list,"张无忌","张三","王二","张三明","马六");
//先找姓张的
ArrayList<String> zhangList = new ArrayList<>();
for (String s : list) {
if(s.startsWith("张")){
zhangList.add(s);
}
}
//在找三个字的
ArrayList<String> threeList = new ArrayList<>();
for (String s : zhangList){
if (s.length() == 3){
threeList.add(s);
}
}
//遍历集合
for (String s : threeList){
System.out.println(s);
}
}
}
结果:
张无忌
张三明
这样写显然我们要进行三次遍历,不但代码多,而且还很浪费功夫,还容易写错。
JDK1.8的新特性中就指明了流的思想,下面让我们看看使用Stream之后的代码吧。
ArrayList<String> list = new ArrayList();
//给集合添加元素
Collections.addAll(list,"张无忌","张三","王二","张三明","马六");
//使用Stream流
list.stream().filter(s->s.startsWith("张"))
.filter(s->s.length() == 3).forEach(s-> System.out.println(s));
结果:
张无忌
张三明
可以看到两个例子的结果完全一致,流的使用简化了很多的代码。
我相信正在读文章的你也很好奇,那么久让我们先看一下流是怎样做到这一点的吧。
使用Stream流解决
我们可以发现,stream流的方法中都有一个参数,而且该参数都是一个接口并且该接口中只有一个抽象方法,我相信看过我上篇Lambda表达式的小伙伴都应该知道,这是符合Lambda表达式的使用条件的,那么就让我们来简化一下吧。
//流的原始方式写法
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张");
}
}).filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() == 3;
}
}).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//流与Lambda表达式结合使用,简化后的代码如下:
list.stream().filter(s->s.startsWith("张"))
.filter(s->s.length() == 3).forEach(s-> System.out.println(s));
从这里可以看到,流的引入给我们带来了很大的便利,下面就让我们充分的认识一下它吧!
获取流的方式
java.util.stream.Stream 是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)
获取一个流非常简单,有以下几种常用的方式:
Collection 集合及其子类都可以通过 .stream() 获取流。
Stream接口的静态方法 .of 可以获取数组对应的流。
//通过单列集合获取流
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//通过Stream接口的静态方法也可以获取流
String[] arr = {"a","b","c"};
Stream<String> Stream1 = Stream.of(arr);
//map方式获取流 基本用不到
HashMap<String, String> map = new HashMap<>();
Stream<String> s1 = map.keySet().stream();
Stream<String> s2 = map.values().stream();
Stream<Map.Entry<String, String>> s3 = map.entrySet().stream();
常用方法
流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
- 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样链式调用。本次介绍的终结方法包括 count 和 forEach 方法。
- 非终结方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为非终结方法。)
方法介绍:
终结方法:不支持链式调用
- count : 统计个数(终结方法,不支持链式调用)
- forEach :逐一处理,遍历的意思(终结方法,不支持链式调用)
其他方法(非终结方法):除了终结方法,其他方法都支持链式调用
- filter : 过滤
- limit : 取前几个
- skip : 跳过前几个
- map : 映射
- static concat : 组合,拼接(只能通过Stream接口调用)
- static of : 获取数组对应的流(只能通过Stream接口调用)
- collect(Collectors接口) : 把流转换成指定的集合
- toArray : 转化成数组
filter与forEach使用
public class Work5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"王佳乐","张三丰","王思聪","张飞","刘晓敏","张靓颖","王敏");
//获取流
Stream<String> stream = list.stream();
//注意:因为已经调用了终结方法,后面就不能使用这个流进行操作了,因为该流已经不存在了,要想操作还需要再次创建新的流
stream.filter(s->s.startsWith("张")).forEach(s-> System.out.println(s));
//流对象已经消失,该语句会报错的
stream.filter(s -> s.startsWith("王")).forEach(s-> System.out.println(s));
}
}
结果:
注意:因为已经调用了终结方法,后面就不能使用这个流进行操作了,因为该流已经不存在了,要想操作还需要再次创建新的流
count使用
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三");
//count是终结方法,调用后此流就不能在使用,不然会报异常,要想使用需要新创建一个流
long count = list.stream().count();
System.out.println(count);
}
}
结果:
2
limit使用
public class Work5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//给集合添加元素
Collections.addAll(list,"王佳乐","张三丰","王思聪","张飞","刘晓敏","张靓颖","王敏");
//获取流
Stream<String> stream = list.stream();
//调用方法 使用limit获取集合前三个并打印
stream.limit(3).forEach(s-> System.out.println(s));
}
}
结果:
王佳乐
张三丰
王思聪
skip使用
public class Work5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//给集合添加元素
Collections.addAll(list,"王佳乐","张三丰","王思聪","张飞","刘晓敏","张靓颖","王敏");
//获取流
Stream<String> stream = list.stream();
//调用方法 使用skip跳过集合中前三个元素并打印
stream.skip(3).forEach(s-> System.out.println(s));
}
}
结果:
张飞
刘晓敏
张靓颖
王敏
map使用
//Person类
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
//测试类
public class Work6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"王佳乐","张三丰","王思聪","张飞");
//把集合中的元素映射到Person对象中并打印
list.stream().map(Person::new).forEach(s-> System.out.println(s));
}
}
结果:
Person{name='王佳乐'}
Person{name='张三丰'}
Person{name='王思聪'}
Person{name='张飞'}
collect(Collectors接口)使用
Collectors接口下的方法:
toList 、 toSet 等等
//Person类
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
//测试类
public class Work6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"王佳乐","张三丰","王思聪","张飞");
//把集合元素映射到Person对象中,并且把流转换成list集合
List<Person> collect = list.stream().map(Person::new).collect(Collectors.toList());
//打印list集合
System.out.println(collect);
}
}
结果:
[Person{name='王佳乐'}, Person{name='张三丰'}, Person{name='王思聪'}, Person{name='张飞'}]
toArray使用
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三");
list.add("王二");
list.add("马六");
list.add("马腾飞");
//获取流,找出姓张的,然后把流转换成数组
Object[] arr = list.stream().filter(s -> s.startsWith("张")).toArray();
System.out.println(Arrays.toString(arr));
}
}
结果:
[张无忌, 张三]
concat使用
注意:concat是静态方法,要使用Stream接口来调用
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三");
ArrayList<String> list1 = new ArrayList<>();
list1.add("王二");
list1.add("马六");
list1.add("马腾飞");
//获取两个集合的流对象
Stream<String> stream = list.stream();
Stream<String> stream1 = list1.stream();
//调用 静态的concat方法
Stream<String> concat = Stream.concat(stream, stream1);
//打印 concat流
concat.forEach(s-> System.out.println(s));
}
}
结果:
张无忌
张三
王二
马六
马腾飞
of使用
注意:of是静态方法,要使用Stream接口来调用
//通过Stream接口的静态方法也可以获取流
String[] arr = {"a","b","c"};
Stream<String> stream = Stream.of(arr);
如果能够帮到你,就留下一个赞吧!