Stream(JDK8新特性)
什么是Stream?
也叫stream流,是JDK8开始新增的一套API(java.util.stream.*),可以用于操作集合或数组中的数据
优势:Stream流大量地结合了Lambda的语法风格来编程,提供了一种更强大,更加简单的方式操作集合或者数组的数据,代码更简洁,可读性更好(比如:从集合中筛选数据,遍历数据)
案例:体验stream流
需求:
把集合中所有以''张''开头而且是三个字的元素存储到一个新的集合中
代码展示:
package com.lyc.steam;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三丰","张无忌","周芷若","赵敏");
//把集合中所有以''张''开头而且是三个字的元素存储到一个新的集合中
//原做法:
ArrayList<Object> list1 = new ArrayList<>();
list.forEach(s -> {
if(s.startsWith("张") && s.length() == 3){
list1.add(s);
}
});
System.out.println(list1);
//stream流优化:
List<String> list2 = list.stream().filter(s -> s.startsWith("张") && s.length() == 3).toList();
System.out.println(list2);
}
}
Stream流的使用步骤
获取数据源的stream流,相当于得到了数据源的一条流水线
调用流水线的各种中间方法去进行数据处理
获取处理的结果,调用一些常见的终结方法
stream的常用方法
获取stream流方法
获取集合的Stream流,
Collection提供的如下方法 | 说明 |
---|---|
default Stream <E> stream() |
获取当前对象的stream流 |
获得数组的Stream流
Arrays类提供的如下方法 | 说明 |
---|---|
public static <T> Stream<T> stream(T[] array) |
获取当前数组的Stream流 |
Stream类提供的如下方法 | 说明 |
---|---|
public static<T> Stream<T> of(T...values) |
获取当前接受数据的stream流 |
案例展示:
public static void main(String[] args) {
//如何获取List集合的stream流?
List<String> list = new ArrayList<>();
Collections.addAll(list,"张三丰","张无忌","周芷若","赵敏");
Stream<String> stream = list.stream();
//如何获得Set集合的stream流?
Set<String> set = new HashSet<>();
Collections.addAll(set,"张三丰","张无忌","周芷若","赵敏");
Stream<String> stream1 = set.stream();
stream1.filter(s->s.contains("张")).forEach(System.out::println);
//如何获得Map集合的stream流?
Map<String,Double> map = new HashMap<>();
map.put("张三丰",9.9);
map.put("张无忌",9.8);
map.put("周芷若",9.7);
map.put("赵敏",9.6);
//map.entrySet()返回的是一个Set集合,所以可以转换为stream流
Stream<Map.Entry<String, Double>> stream2 = map.entrySet().stream();
stream2.filter(s->s.getValue()>9.5 && s.getKey().contains("张")).forEach(System.out::println);
//如何获取数组的数据流
String[] arr = {"张三丰","张无忌","周芷若","赵敏"};
//直接使用Array工具类的静态方法
Stream<String> stream3 = Arrays.stream(arr);
//使用Stream工具类
Stream<String> arr1 = Stream.of(arr);
Stream流中间方法
中间方法是指调用完成后返回新的Stream流,可以继续使用(支持链式编程)
方法名 | 说明 |
---|---|
Stream<T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream<T> limit(long maxSize) | 获取前几个元素 |
Stream<T> skip(long n) | 跳过前几个元素 |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream<T> distinct() | 去重 |
Stream<T> sorted() | 排序 |
Stream<T> sorted(Comparator comparator) | 根据提供的Comparator进行排序 |
<R> Stream<R> map(Function mapper) | 对元素进行加工,并返回对应的新流 |
IntStream mapToInt(ToIntFunction mapper) | 返回一个IntStream其中包含将给定函数应用于此流的元素的结果 |
代码测试:
public static void main(String[] args) {
List<Double> sorces = new ArrayList<>();
Collections.addAll(sorces, 88.5, 99.5, 100.0, 60.5, 70.5, 80.5, 90.5, 50.5, 40.5, 30.5, 20.5);
//需求1:找出成绩大于六十的学生成绩,并升序后输出 终结方法:foreach
sorces.stream().filter(s->s>60).sorted().forEach(System.out::println);
System.out.println("----------------------------------------------------------");
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("张三", 18, 170.7));
students.add(new Student("李四", 19, 180.7));
students.add(new Student("李四", 19, 180.7));
students.add(new Student("王五", 20, 190.7));
students.add(new Student("赵六", 21, 200.7));
students.add(new Student("钱七", 22, 210.7));
students.add(new Student("孙八", 23, 220.7));
//需求2:找出年龄大于等于20,小于30的学生,并按照年龄降序排序输出
students.stream().filter(s->s.getAge()>=20 && s.getAge()<30)
.sorted((s1,s2)->s2.getAge()-s1.getAge())
.forEach(System.out::println);
System.out.println("-------------------------------------------------------");
//需求3:找出身高最高的三名学生 limit 方法:限制数量
students.stream()
.sorted((s1,s2)->s2.getHeight().compareTo(s1.getHeight()))
.limit(3).forEach(System.out::println);
System.out.println("------------------------------------------------------------");
//需求4:取出身高倒数的2名学生,并输出 skip方法:跳过
students.stream().sorted((s1,s2)->s2.getHeight().compareTo(s1.getHeight()))
.skip(students.size()-2).forEach(System.out::println);
System.out.println("------------------------------------------------------------");
//需求5:找出身高大于等于180cm的学生的名字,要求去除重复的名字,在输出 map方法:映射,将student对象的name属性映射为字符串 distinct 方法:去重
students.stream().filter(s->s.getHeight()>=180).distinct().map(Student::getName)
.forEach(System.out::println);
System.out.println("----------------------------------------------------------------");
//distinct()方法:去重,自定义类型的对象,必须重写hashCode()和equals()方法,才能去重
students.stream().filter(s->s.getHeight()>=180).distinct()
.forEach(System.out::println);
System.out.println("---------------------------------------------------------");
//需求6:合并以下的两个流 concat 方法:连接两个流
Stream<String> st1 = Stream.of("张三", "李四", "王五");
Stream<String> st2 = Stream.of("赵六", "钱七", "孙八");
Stream<String> stream = Stream.concat(st1, st2);
stream.forEach(System.out::println);
}
}
stream流的终结方法
终结方法是指调用完成后,不会再返回新的stream流,没法在使用流了
stream提供的常用终结方法 | 说明 |
---|---|
void forEach(Consmer) |
对此流运算后的元素执行便历 |
long count() |
统计此流运算后的元素个数 |
Optional <T> max(Comparator<? super T> Comparator) |
获取此流运算后的最大值元素 |
Optional <T> min(Comparator<? super T> Comparator) |
获取此流运算后的最小值元素 |
收集Stream流:就是把Stream流操作后的结果转到集合或者数组中去返回。
stream流:方便操作集合/数组的手段 集合/数组:才是开发的目的
stream提供的常用终结方法 说明 R collect(Collector collector)
把流处理后的结果收集到一个指定的集合中去 Object[] toArray()
把流处理后的结果收集到一个数组中去
代码展示:
package com.lyc.steam;
import com.lyc.pojo.Student;
import java.util.*;
import java.util.stream.Collectors;
//测试stream流的终结方法
public class Test4 {
public static void main(String[] args) {
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("张三", 18, 170.7));
students.add(new Student("李四", 19, 180.7));
students.add(new Student("李四", 19, 180.7));
students.add(new Student("王五", 20, 190.7));
students.add(new Student("赵六", 21, 200.7));
students.add(new Student("钱七", 22, 210.7));
students.add(new Student("孙八", 23, 220.7));
//需求1:请计算出身高超过180的学生人数
long count = students.stream().filter(s -> s.getHeight() > 180).count();
System.out.println(count);
System.out.println("-----------------------------------------------");
//需求2:找出身高最高的学生对象,并输出
Student max = students.stream().max((s1, s2) -> s1.getHeight().compareTo(s2.getHeight())).get();
System.out.println(max);
System.out.println("-------------------------------------------");
//需求3:找出身高最矮的学生对象,并输出
Student min = students.stream().min((s1, s2) -> s1.getHeight().compareTo(s2.getHeight())).get();
System.out.println(min);
System.out.println("----------------------------------------------");
//需求4:身高超过190的学生对象,放在一个新的集合中返回
// toList()方法:将流中的元素收集到一个List集合中,返回一个List集合
//流,只能使用一次,所以不能再使用filter()方法,否则会报错
List<Student> students1 = students.stream().filter(s->s.getHeight()>190).toList();
Set<Student> collect = students.stream().filter(s -> s.getHeight() > 190).collect(Collectors.toSet());
System.out.println(students1);
System.out.println(collect);
System.out.println("--------------------------------------------------");
//需求5:找出身高大于等于190cm的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。 key:学生姓名,value:学生身高,toMap()方法:将流中的元素收集到一个Map集合中,返回一个Map集合
Map<String, Double> map = students.stream().filter(s -> s.getHeight() >= 170).distinct().collect(Collectors.toMap(Student::getName, Student::getHeight));
System.out.println(map);
System.out.println("----------------------------------------------");
//需求6:找出身高大于等于180cm的学生对象,并把学生对象的名字存入到一个数组返回。
String[] array = students.stream().filter(s -> s.getHeight() >= 180).map(Student::getName).toArray(len->new String[len]);
System.out.println(Arrays.toString(array));
}
}
注:流只能收集一次,不要想着将重复的流代码抽取封装成工具,会报错
流只是我们用来简化代码的工具,只是手段,变成集合/数组才是目的!
希望对大家有所帮助!