什么是stream?
也叫Stream流,是jdk8新增的一套API(java.util.stream.*)可以用于操作集合或者数组的数据。
优势:Stream流大量的结合了Lambda语法的风格编程,提供了一种更加强大,更加简单的方式操作或者数组中的数据,代码更简洁,可读性更好。
体验Stream流
原来的操作方法
ArrayList<String> list1 = new ArrayList<String>();
list1.add("赵无极");
list1.add("赵敏");
list1.add("张双");
list1.add("张三a");
list1.add("周娅");
//1.把所有以“张”开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for(String name : list1){
if(name.startsWith("张")){
list2.add(name);
}
}
System.out.println(list2);
//把“张”开头的,长度为3的元素再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for(String name : list2){
if(name.length() == 2){
list3.add(name);
}
}
System.out.println(list3);
是不是很繁琐,那我们就用Stream流来试一下。
我们先拿到这个集合,去调它的一个方法叫stream,得到Stream流方法,而它也支持链式编程的,可以继续用点(.)来调用它的方法,调用filter方法,这个方法的作用是过滤。
list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name->System.out.println(name));
-
list1.stream()
将
list1
集合转换成一个流。流是Java 8引入的一个抽象概念,它可以对集合进行各种高效的聚合操作。 -
.filter(name->name.startsWith("张"))
使用
filter
方法对流中的元素进行筛选。name->name.startsWith("张")
是一个Lambda表达式,它定义了一个谓词(Predicate),用于检查每个元素(这里是name
)是否以"张"开头。只有满足这个条件的元素才会被保留在流中。 -
.filter(name->name.length()==3)
再次使用
filter
方法对已经筛选过的流进行进一步筛选。这次的筛选条件是元素的长度是否等于3。同样,只有满足这个条件的元素才会被保留在流中。 -
.forEach(name->System.out.println(name))
使用
forEach
方法对筛选后的流中的每个元素执行操作。name->System.out.println(name)
是一个Lambda表达式,它定义了对每个元素执行的操作,即打印出每个元素。
Stream流的使用步骤
图片的形式展示
常见方法
如何获取Stream流?
获取集合的Stream流
//Collection提供的如下方法
default Stream<E> stream();
获取数组的Stream流
//Arrays类提供的如下方法
public static <T> stream(T[] array);
//Stream类提供的如下方法
public static Stream<T> of(T...values);
例题
1.如何获取List集合的Stream流?
List<String> names = new ArrayList<>();
Collections.addAll(names,"张三丰","张无忌","周志","赵明");
Stream<String> stream = names.stream();
stream.filter(n -> n.length()>2).forEach(n -> System.out.println(n));//张三丰 张无忌
2.如何获取Set集合的Stream流?
Set<String> set = new HashSet<>();
Collections.addAll(set,"张三丰","张无忌","周志","赵明");
Stream<String> stream1 = set.stream();
stream1.filter(n -> n.contains("三")).forEach(n -> System.out.println(n));//张三丰
3.如何获取Map集合的Stream流?
Map集合不能直接使用stream调用Stream流,因为Stream方法是Collection提供的,Map集合不属于Collection。
keySet()
: 返回映射中包含的键的Set
视图。此方法返回的集合支持通过流操作处理映射中的所有键。values()
: 返回映射中包含的值的Collection
视图。此方法返回的集合支持通过流操作处理映射中的所有值。entrySet()
: 返回映射中包含的键值对的Set
视图。此方法返回的集合支持通过流操作处理映射中的所有键值对(Map.Entry
)。
Map<String, String> map = new HashMap<>();
map.put("张三", "30");
map.put("李四", "25");
map.put("张伟", "35");
map.put("王五", "40");
// 对Map的值进行流操作
map.values().stream()
.filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(name -> System.out.println(name));
// 对Map的键进行流操作
map.keySet().stream()
.filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(name -> System.out.println(name));
// 对Map的键值对进行流操作
map.entrySet().stream()
.filter(entry -> entry.getValue().startsWith("张"))
.filter(entry -> entry.getValue().length() == 3)
.forEach(entry -> System.out.println(entry.getKey()));
4.如何获取数组的Stream流?
String[] names2= {"张翠山“,”东方不败”,”唐大山”,”独孤求败”};
Stream< String> s1= Arrays. stream(names2);
Stream< String> s2= Stream. of(names2);| I
Arrays.stream()
是一个静态方法,它接受一个数组作为参数,并返回一个流,该流包含数组中的所有元素。Stream.of()
是一个静态方法,它接受一系列参数,并返回一个包含这些参数的流。
Stream流常见的中间方法
中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。
示例:
需求1:找出成绩大于等于60分的数据,并升序后,再输出。
List<Double> scores = new ArrayList<Double>();
Collections.addAll(scores,88.5,100.0,68.0,99.8,9.5);
scores.stream().filter(score -> score > 88.5).forEach(score -> System.out.println(score));//100.0 99.8
需求2,找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出。
List< Student> students = new ArrayList<>();
Student s1= new Student(name: "蜘蛛精", age:26, height:172.5);
Student s2= new Student(name: "蜘蛛精", age:26, height:172.5);
Student s3 = new Student(name: "紫霞", age: 23, height:167.6);
Student s4= new Student(name: "白晶晶", age:25, height:169.0);
Student s5= new Student(name: "牛魔王", age:35, height:183.3);
Student s6= new Student(name: "牛夫人", age:34, height:168.5);
Collections. addAll(students, s1, s2, s3, s4, s5, s6);
//需求2:找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出。
students. stream(). filter(s - > s. getAge() >=23&& s. getAge() <= 30)
. sorted(). forEach(s - > System. out. println(s));
该程序会报错是因为sorted方法不知道该以什么为依据进行排序,
如果我们想要按照年龄进行排序,就需要重载sort方法,用Lambda表达式指定排序的方法。
students. stream(). filter(s - > s. getAge() >=23&& s. getAge() <=30). sorted((o1, o2) - > o2. getAge() - o1. getAge()). forEach(s - > System. out. println(s));
需求3:取出身高最高的前3名学生,并输出。
Double类型不能直接作差,用Double的一个compare方法
students. stream().sorted((o1, o2) - > Double.compare(o2.getHeight(), o1.getHeight())). limit(3). forEach(s - > System. out. println(s));|
需求4:取出身高倒数的2名学生,并输出。
students. stream().sorted((o1, o2) - > Double.compare(o2.getHeight(), o1.getHeight())). skip(students. size() -2). forEach(System. out:: println);
需求5:找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出
students. stream(). filter(s - > s. getHeight() >168). map(Student::getName). distinct(). forEach(System. out:: println);
distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode, equals)
合并两个流为一个流
Stream< String> st1= Stream. of("张三“,”李四”);
Stream< String> st2= Stream. of("张三2", "李四2", "王五“);
Stream< String> allSt = Stream. concat(st1, st2);
allSt.forEach(System.out::println);
如果两个流的类型不样,那么最后合并的流类型用object。
Stream流常见的终结方法
终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。
示例
List< Student> students = new ArrayList<>();
Student s1= new Student( "蜘蛛精",26,172.5);
Student s2= new Student( "蜘蛛精",26,172.5);
Student s3 = new Student( "紫霞", 23, 167.6);
Student s4= new Student( "白品品", 25,169.0);
Student s5= new Student( "牛魔王",35, 183.3);
Student s6= new Student("牛夫人",34, 168.5);
Collections. addAll(students, s1, s2, s3, s4, s5, s6);
需求1:请计算出身高超过168的学生有几人。
long size = students.stream().filter(higher -> higher.getHeight() > 168).count();
System.out.println(size);//5
需求2:请找出身高最高的学生对象,并输出。
Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(s);
//Student{name='牛魔王', age=35, height=183.3}
需求3:请找出身高最矮的学生对象,并输出。
Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(ss);
//Student{name='紫霞', age=23, height=167.6}
需求4:请找出身高超过170的学生对象,并放到一个新集合中去返回。
流只能收集一次
List< Student> students1= students. stream(). filter(a - > a. getHeight() >170). collect(Collectors. toList());
System. out. println(students1);
Set< Student> students2= students. stream(). filter(a - > a. getHeight() >170). collect(Collectors. toSet());
System. out. println(students2);
需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。
Map< String, Double> map =students. stream(). filter(a - > a. getHeight() >170). distinct(). collect(Collectors. toMap(a - > a. getName(), a - > a. getHeight()));
System. out. println(map);
总结:
“Stream 不仅是一种 API,更是思维方式的升级——从‘如何做’到‘做什么’。掌握它,你的代码会变得更简洁、更富有表达力。现在就去试试吧!”