目录
一、简介
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作。
二、Stream流的应用
2.1 为什么使用stream流
当我们对集合中的元素进行操作的时候,除了必须的添加、删除、获取外,最典型的就是集合遍历。我们可以来展示一下集合操作数据的弊端,需求如下:
需求:
一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,孙悟空,张三丰,张三
1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
package demo01;
import java.util.ArrayList;
import java.util.List;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 14:28
*/
public class Test {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,孙悟空,张三丰,张三
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("孙悟空");
list.add("张三丰");
list.add("张三");
//1. 拿到所有姓张的人名
List<String> newList01 = new ArrayList<>();
for (String s : list) {
if(s.startsWith("张")){//startsWith--以...开头
newList01.add(s);
}
}
//2.拿到名字长度为3个字的
ArrayList<String> newList02 = new ArrayList<>();
for (String s : newList01) {
if(s.length()==3){
newList02.add(s);
}
}
//3.打印这些数据
for (String s : newList02) {
System.out.println(s);
}
}
}
分析:
循环遍历的弊端
这段代码中含有三个循环,每一个的作业都不同
1.首先筛选张姓的人
2.然后筛选名字有三个字的人
3.最后进行对结果进行打印输出
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。
那Stream能给我们带来怎样更加方便的写法呢?
Stream初体验
package demo01;
import java.util.ArrayList;
import java.util.List;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 14:28
*/
public class Test {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,孙悟空,张三丰,张三
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("孙悟空");
list.add("张三丰");
list.add("张三");
list.stream().filter(t->t.startsWith("张")).filter(t->t.length()==3).forEach(item-> System.out.println(item));
}
}
2.2 Stream流的原理
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
2.3 步骤
- 获取Stream流对象
- 中间操作---返回类型还是Stream流对象
- 终止操作---不再是Stream流对象
2.4 获取Stream流对象的方式
- 通过集合对象调用stream()
- 通过Arrays获取stream流对象
- 通过Stream流里面of方法
package demo02;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 15:36
*/
public class Test02 {
public static void main(String[] args) {
//第一种通过集合对象调用
List<String> list=new ArrayList<>();
Stream<String> stream = list.stream();
//第二种使用Arrays工具类
String[] arr={};
Stream<String> stream1 = Arrays.stream(arr);
//第三种:Stream类
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
//上面都是串行流
}
}
- 还有一种并行流(效率提高,但不确定输出顺序)
package demo02;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 15:36
*/
public class Test02 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
Stream<String> stringStream = list.parallelStream();
stringStream.forEach(System.out::println);
}
}
2.5 Stream流的API方法
例子:
假设有一个Person类和一个Person列表,现在有两个需求:
1. 找到年龄大于18岁的人并输出;
2. 找出所有中国人的数量。
3. 找出年龄最大和最小
package demo03;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 15:52
*/
public class Test03 {
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(item->item.getAge()>18).forEach(System.out::println);
//2. 找出中国人 并统计个数: count()
long count = personList.stream().filter(item -> item.getCountry().equals("中国")).count();
System.out.println("中国人的数量为:"+count);
//3.找出年龄最大和最小
Person person1 = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge()).get();
Person person2 = personList.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
System.out.println("年龄最大:"+person1);
System.out.println("年龄最小:"+person2);
}
}
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 + "}";
}
}
2.5.1 map
会把集合中的元素转化为另一种类型
如上述案例---查询到来自中国的人民和年龄
personList.stream().filter(item->item.getCountry().equals("中国")).map(item->new P(item.getName(),item.getAge())).forEach(System.out::println);
案例2:
package demo04;
import java.util.Arrays;
import java.util.List;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 16:18
*/
public class Test04 {
public static void main(String[] args) {
//整数数组每个元素+3
List<Integer> list = Arrays.asList(1, 17, 27, 7);
list.stream().map(item -> item + 3).forEach(System.out::println);
List<String> list2 = Arrays.asList("hello", "world", "java", "spring", "springmvc");
//字符串大写
list2.stream().map(String::toUpperCase).forEach(System.out::println);
}
}
2.5.2 collect 收集
package demo05;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 16:21
*/
public class Test05 {
public static void main(String[] args) {
List<Person5> personList = new ArrayList<>();
personList.add(new Person5("小梅",24,"中国",'F'));
personList.add(new Person5("欧阳雪",18,"中国",'F'));
personList.add(new Person5("Tom",24,"美国",'M'));
personList.add(new Person5("Harley",22,"英国",'F'));
personList.add(new Person5("向天笑",20,"中国",'M'));
personList.add(new Person5("李康",22,"中国",'M'));
personList.add(new Person5("Jack",21,"中国",'F'));
personList.add(new Person5("李四",22,"中国",'M'));
//把Person-年龄大于20人--里面的名称----新的集合。
personList.stream().filter(item->item.getAge()>20).map(item->item.getName()).collect(Collectors.toList()).forEach(System.out::println);
}
}
class Person5{
private String name;
private Integer age;
private String country;
private char sex;
public Person5() {
}
public Person5(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 "Person5{name = " + name + ", age = " + age + ", country = " + country + ", sex = " + sex + "}";
}
}
2.5.3 sorted 排序
//根据年龄排序
List<Person5> collect = personList.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList());
System.out.println(collect);
2.5.4 reduce 规约
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
例子:
求[1,2,3,4]的乘积
package demo06;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* @author huihui
* @Project jdk8_stream
* @date 2023/6/14 16:30
*/
public class Test06 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 5);
Optional<Integer> reduce = list.stream().reduce((t1, t2) -> t1 * t2);
//t1=1, t2=2 ===>2
// t1=2 t2=3===>6
// t1=6 t2=5====>30
System.out.println(reduce.get());
}
}
2.5.5 findFirst 查询第一个
//查询年龄在18和20直接的一个
Optional<Person5> first = personList.stream().filter(item->item.getAge()>=18&&item.getAge()<=20).findFirst();
System.out.println(first.get());