Stream流
什么是Stream流
Stream是JAVA8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找,过滤,筛选等操作
为什么使用Stream流
当我们需要对集合的元素进行操作的时候,除了必须的添加,删除,获取外,最典型的就是集合遍历。我们来体验集合操作数据的弊端,需求如下:
一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3. 打印这些数据
public class Test {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("张无忌");
names.add("周芷若");
names.add("赵敏");
names.add("张强");
names.add("张三丰");
//拿到所有姓张的名字
ArrayList<String> zhang = new ArrayList<>();
for (String s : names) {
//判断s前缀是否是张
if(s.startsWith("张")){
zhang.add(s);
}
}
//拿到名字长度为三个字的
ArrayList<String> san = new ArrayList<>();
for (String s : zhang) {
if(s.length()==3){
san.add(s);
}
}
//打印这些数据
for (String s : san) {
System.out.println(s);
}
}
}
分析
循环遍历的弊端
这段代码中有三个循环,每一个作用不同:
1.首先筛选所有姓张的人;
2.然后筛选名字有三个字的人;
3.最后进行对结果的输出打印
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环,循环,再循环。 这显然不是理所应当的,而是我们完成业务的一种方式而已,每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能使用另一个循环从头开始
那Stream能给我们带来怎样更加优雅的写法呢?
Stream初体验
public class Test {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("张无忌");
names.add("周芷若");
names.add("赵敏");
names.add("张强");
names.add("张三丰");
//过滤出姓张并且姓名长度为3的名字
names.stream().filter(t->t.startsWith("张")).filter(t->t.length()==3).forEach(System.out::println);
}
}
Stream流的原理
Stream流的思想类似于工厂车间的"生产流水线",Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream流的操作步骤
一、创建Stream流
从一个数据源,如集合,数组中获取流
二、中间操作
一个操作的中间链,对数据源的数据进行操作。---返回的类型还是Stream流对象
三、终止操作
返回类型不再是Stream流对象
获取Stream流对象的方式
1.通过集合对象调用Stream()方法
//通过集合调用stream流方法
ArrayList<String> strings = new ArrayList<>();
Stream<String> stream = strings.stream();
2.通过Arrays获取Stream流对象
//通过Arrays工具类获取
String[] arr ={};
Stream<String> stream1 = Arrays.stream(arr);
3.通过Stream流里面的of方法
//通过Stream类获取
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 1, 5, 7);
以上三种都是串行流输出的是一个一个执行,而并行流相当于同时有多个线程同时执行该流速度更快,但是输出顺序是随机的,下面例子为并行流 parallelStream
//并行流
ArrayList<String> names = new ArrayList<>();
names.add("张无忌");
names.add("周芷若");
names.add("赵敏");
names.add("张强");
names.add("张三丰");
Stream<String> stringStream = names.parallelStream();
stringStream.forEach(System.out::println);
Stream流的api方法
筛选filter,forEach循环 统计个数 count 找到最大值max 找到最小值min的使用方法
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//1. 年龄大于18 filter:过滤掉不满足条件的元素. forEach:输出元素. ---如果没有终止函数,那么中间函数的代码不会被执行。
personList.stream().filter(t->t.getAge()>18).forEach(System.out::println);
//2. 找出中国人 并统计个数: count()
long count = personList.stream().filter(t -> t.getCountry().equals("中国")).count();
System.out.println("中国人有"+count);
//3.找出年龄最大和年龄最小的人 max min
Optional<Person> max = personList.stream().max((t1, t2) -> t1.getAge() - t2.getAge());
Person person = max.get();
System.out.println("年龄最大的人是"+person);
Optional<Person> min = personList.stream().min((t1, t2) -> t1.getAge() - t2.getAge());
Person person1 = min.get();
System.out.println("年龄最小的人是"+person1);
}
map-->把集合中的元素转换成另一种类型
map会把集合中的元素转换成另一种类型
public class Test {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//使用map将姓名剥离并且打印出来,结果为string类型的集合,与之前的不同
personList.stream().map(Person::getName).forEach(System.out::println);
//使用map集合剥离姓名和年龄使用student类接收
personList.stream().map(t->new Student(t.getName(),t.getAge())).forEach(t-> System.out.println(t));
}
}
class Student{
String name;
Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
class Person {
private String name;
private Integer age;
private String country;
private char sex;
public Person() {
}
public Person(String name, Integer age, String country, char sex) {
this.name = name;
this.age = age;
this.country = country;
this.sex = sex;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* 获取
* @return country
*/
public String getCountry() {
return country;
}
/**
* 设置
* @param country
*/
public void setCountry(String country) {
this.country = country;
}
/**
* 获取
* @return sex
*/
public char getSex() {
return sex;
}
/**
* 设置
* @param sex
*/
public void setSex(char sex) {
this.sex = sex;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + ", country = " + country + ", sex = " + sex + "}";
}
}
收集--->collect 把处理过的集合搜集成新的集合
把处理过的集合搜集成新的集合
过滤出年龄大于20岁,将大于20岁的人的名字封装成一个新的集合
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//过滤出年龄大于20岁,将大于20岁的人的名字封装成一个新的集合
List<String> collect = personList.stream().filter(t -> t.getAge() > 20).map(t -> t.getName()).collect(Collectors.toList());
System.out.println(collect);
stream流排序方法--->sorted
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//将集合中的元素按照年龄排序,之后封装到新的集合中
List<Person> collect1 = personList.stream().sorted((t1, t2) -> t1.getAge() - t2.getAge()).collect(Collectors.toList());
System.out.println(collect1);
reduce--->规约
规约,也称为缩减,是把一个流缩减成一个值,能实现对集合求和,求乘积和求最值的操作
List<Integer> integers = Arrays.asList(1, 2, 3, 5);
Optional<Integer> reduce = integers.stream().reduce((t1, t2) -> t1 + t2);
//t1==1 t2==2 ===3
//t1==3 t2==3 ====6
//t1==6 t2==5 ====11
Integer x = reduce.get();
System.out.println(x);
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//求集合中所有的年龄之和
Optional<Integer> reduce = personList.stream().map(t -> t.getAge()).reduce((t1, t2) -> t1 + t2);
Integer integer = reduce.get();
System.out.println(integer);
匹配--->find
匹配第一个元素 ---findFirst
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//匹配第一个对象
Optional<Person> first = personList.stream().findFirst();
Person person = first.get();
System.out.println(person);
提取、组合
中间的操作: filter map sorted distinct() skip limit()
终止操作: forEach count() reduce() collect(Collectors.toList()) findFirst max min