Stream流体验
- 案例需求: 有一个List集合,元素有
"张三丰","张无忌","周芷若","赵敏","张强",找出姓张,且是3个字的名字,存入到一个新集合中去。
集合玩法
java
public class StreamDemo1 {
public static void main(String[] args) {
// 目标:认识Stream流,掌握其基本使用步骤。体会它的优势和特点。
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张翠山");
// 1、先用传统方案:找出姓张的人,名字为3个字的,存入到一个新集合中去。
List<String> newList = new ArrayList<>();
for (String name : list) {
if(name.startsWith("张") && name.length() == 3){
newList.add(name);
}
}
System.out.println(newList);
}
}
Stream流玩法
- 用Stream流来做,代码是这样的(ps: 是不是像流水线一样,一句话就写完了)
scss
// 2、使用Stream流解决
List<String> newList2 = list.stream().filter(
s -> s.startsWith("张")).filter(
s -> s.length() == 3).collect(Collectors.toList());
System.out.println(newList2);
先不用知道这里面每一句话是什么意思,具体每一句话的含义,待会再一步步学习。现在只是体验一下。 学习Stream流我们接下来,会按照下面的步骤来学习。
Stream流的操作步骤

获取Stream流
- 接下来我们正式来学习Stream流。先来学习如何创建Stream流、或者叫获取Stream流。
- 主要掌握下面三点:
- 如何获取单列集合List集合的Stream流?
- 如何获取Map集合的Stream流?
- 如何获取数组的Stream流?
语法
-
获取集合的Stream流
Collection提供的如下方法 说明 default Stream stream() 获取当前集合对象的Stream流 - 注意:map无法直接获取流,需要转换为单列集合再获取,如Entry对象
-
获取数组的Stream流(两种方式)
Arrays类提供的如下 方法 说明 public static Stream stream(T[] array) 获取当前数组的Stream流 Stream类提供的如下 方法 说明 public static Stream of(T... values) 获取当前接收数据的Stream流 -
代码演示
javaimport java.util.*; import java.util.stream.Stream; // 目标:获取stream流。 // 1、单列集合获取流的方法都是:调用stream()方法 // 2、Map集合获取stream()流。 // 创建map集合 // 获取map集合的键流 // 获取map集合的值流 // 获取map集合的键值对对象流 // 3、获取数组的流。 //准备数组 String[] arr = {"张三丰", "张无忌", "赵敏", "周芷若"}; //方式1:Arrays.stream(数组) //方式2:Stream.of(数组) public class Demo012 { public static void main(String[] args) { // 目标:获取stream流。 // 1、单列集合获取流的方法都是:调用stream()方法 List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); Stream<String> stream1 = list.stream(); Stream<Object> stream2 = new HashSet<>().stream(); Stream<Object> stream3 = new LinkedHashSet<>().stream(); Stream<Object> stream4 = new LinkedList<>().stream(); // 2、Map集合获取stream()流。(注意:map无法直接获取流,需要转换为单列集合再获取) // 创建map集合 Map<String,String> map = new HashMap<>(); // 获取map集合的键流 Stream<String> stream5 = map.keySet().stream(); // 获取map集合的值流 Stream<String> stream6 = map.values().stream(); // 获取map集合的键值对对象流 Stream<Map.Entry<String, String>> stream7 = map.entrySet().stream(); // 3、获取数组的流。 //准备数组 String[] arr = {"张三丰", "张无忌", "赵敏", "周芷若"}; //方式1:Arrays.stream(数组) Stream<String> stream8 = Arrays.stream(arr); //方式2:Stream.of(数组) Stream<String> stream9 = Stream.of(arr); } }
可变参数
-
就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型...参数名称;
-
可变参数的特点和好处
- 特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。
- 好处:常常用来灵活的接收数据。
-
可变参数的注意事项:
- 可变参数在方法内部就是一个数组。
- 可变参数必须放在形参列表的最后面(写在前面传值时无法分辨从第几个开始不是可变参数)
- 一个形参列表中可变参数只能有一个(多个传值时无法分辨从哪里开始是下一个可变参数的值)
-
代码演示
javapublic static void main(String[] args) { //目标:调用可变参数方法 //作用:传递参数灵活 //传递1个参数 demo("hello"); //传递多个参数 demo("hello","a","b","c"); //传递一个数组 demo(new String[]{"a","b","c"}); } public static void demo(String... str){ //str本质是一个数组 System.out.println("str数组内存地址:"+str); System.out.println("str数组内存地址:"+ Arrays.toString(str)); System.out.println("str数组元素的个数:"+ str.length); System.out.println("------------------------------------"); } // public static void demo2(String... str,Integer abc){ //错误,可变参数必须放到参数列表最后 // //str本质一个数组 // System.out.println(Arrays.toString(str)); // System.out.println(str.length); // System.out.println("----------------------"); // } // public static void demo2(String... str,Integer... abc){ //错误,可变参数最多只有一个 // //str本质一个数组 // System.out.println(Arrays.toString(str)); // System.out.println(str.length); // System.out.println("----------------------"); // } -
通过段点也可以看到,本质上是数组

Stream流中间方法
-
学习了创建Stream流的方法。接下来我们再来学习,Stream流中间操作的方法。
-
中间方法指的是:调用完方法之后其结果是一个新的Stream流,于是可以继续调用方法,这样一来就可以支持链式编程(流式编程)
Stream提供的常用中间方法 说明 Stream filter(Predicate<? super T> predicate) 用于对流中的数据进行过滤。 Stream<T> sorted() 对元素进行升序排序 Stream<T> sorted (Comparator<? super T> comparator) 按照指定规则排序 Stream limit (long maxSize) 获取前几个元素 Stream skip (long n) 跳过前几个元素 Stream distinct () 去除流中重复的元素。(对象需重写hasCode和equals方法) Stream map (Function<? super T, ? extends R> mapper) 对元素进行加工,并返回对应的新流 static Stream concat (Stream a, Stream b) 合并a和b两个流为一个流 javaimport java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; public class Demo014 { public static void main(String[] args) { // 目标:搞清楚Stream流提供的中间方法。 List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); list.add("张无忌"); // 1、过滤:筛选数据的,查找姓"张",并遍历 list.stream().filter(name->name.startsWith("张")).forEach(System.out::println); System.out.println("--------------"); // 2、排序的:sorted 默认是升序。 list.stream().sorted().forEach(System.out::println); System.out.println("--------------"); // 3、集合中是对象的排序(要么对象实现Comparable接口,要么重写比较方法) List<Student> students = new ArrayList<>(); students.add(new Student("小明", 18, 90.0, "北京")); students.add(new Student("小明", 18, 90.0, "北京")); students.add(new Student("小花", 21, 60.0, "深圳")); students.add(new Student("小红", 19, 80.0, "上海")); students.add(new Student("小刚", 20, 70.0, "广州")); //按照年龄升序(实现Comparable接口) students.stream().sorted().forEach(System.out::println); //这里对于对象类型默认安装student类型里面实现Comparable接口进行排序 System.out.println("--------------"); //按照分数降序排序(重写比较方法) students.stream().sorted((o1, o2) -> Double.compare(o2.getScore(),o1.getScore())).forEach(System.out::println); System.out.println("--------------"); // 4、limit 取前几个 list.stream().limit(3).forEach(System.out::println); System.out.println("--------------"); // 5、跳过前几个:skip list.stream().skip(3).forEach(System.out::println); System.out.println("--------------"); // 6、加工方法:map //map加工后返回元素类型可以与原集合元素类型不一样,返回元素的类型由map里面决定 students.stream().map(new Function<Student, String>() { @Override public String apply(Student student) { return student.getName()+","+student.getScore(); } }).forEach(System.out::println); // 简写形式: students.stream().map( student -> student.getName() + "," + student.getScore() ).forEach(System.out::println); System.out.println("--------------"); // 7、合并流:两个流(list集合流,list2集合流)合并成一个流。 // Stream<String> stream1 = list.stream(); // Stream<Double> stream2 = list2.stream(); // Stream<? extends Serializable> stream = Stream.comcat(stream1,stream2); // // Serizalizable是list集合的父类,这里的Stream流存放的是集合,所以存放了集合的父类 Stream.concat(list.stream(),students.stream()).forEach(System.out::println); System.out.println("--------------"); //8、去重 distinct list.stream().distinct().forEach(System.out::println); System.out.println("--------------"); students.stream().distinct().forEach(System.out::println); //如果是对象类型会调用对象的hashCode()和equals()去重,因为distinct也是根据equals和hasCode来判断去重的 } }

Stream流的终结方法、收集Stream流
Stream流的终结方法
-
终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。
Stream提供的常用终结方法 说明 void forEach(Consumer action) 对此流运算后的元素执行遍历 long count() 统计此流运算后的元素个数 Optional<T> max(Comparator<? super T> comparator) 获取此流运算后的最大值元素 Optional<T> min(Comparator<? super T> comparator) 获取此流运算后的最小值元素
java
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class Demo015 {
public static void main(String[] args) {
// 目标:学习Stream流的终结方法。
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张无忌");
// 1、遍历方法
list.stream().distinct().forEach(System.out::println);
// 2、统计数据的个数 count()
System.out.printf("去重后的个数:%d%n",list.stream().distinct().count());
// 3、挑选出最小值
Optional<String> optional = list.stream().min(
(o1, o2) -> o1.compareTo(o2));
// 字符串对比,用compareTo方法
//按照升序取第一个
if(optional.isPresent()){
//判断是否存在符合要求的结果
String min = optional.get();
//注意:当没有符合的结果这句代码会报错,所以为了安全需要进行optional.isPresent()
System.out.println("最小的姓名:"+min);
}
List<Student> students = new ArrayList<>();
students.add(new Student("小明", 18, 90.0, "北京"));
students.add(new Student("小红", 19, 80.0, "上海"));
students.add(new Student("小刚", 20, 70.0, "广州"));
students.add(new Student("小花", 21, 60.0, "深圳"));
// 4、挑选出最大值
Optional<Student> optional2 = students.stream().max(
(o1, o2) -> Double.compare(o1.getScore(), o2.getScore()));
//按照升序取最后一个
if(optional2.isPresent()){
Student student = optional2.get();
System.out.println("最大成绩学生:"+student);
}
}
}
收集Stream流
-
收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回。
Stream提供的常用终结方法 说明 R collect(Collector collector) 把流处理后的结果收集到一个指定的集合中去 Object[] toArray() 把流处理后的结果收集到一个数组中去 Collectors工具类提供了具体的收集方式 说明 public static Collector toList() 把元素收集到List集合中 public static Collector toSet() 把元素收集到Set集合中 public static Collector toMap(Function keyMapper , Function valueMapper) 把元素收集到Map集合中 javaimport java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; public class Demo016 { public static void main(String[] args) { // 目标:收集Stream流。把流收集成集合: 流只能用一次 List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); list.add("张无忌"); // 收集List集合 List<String> list1 = list.stream().distinct().toList(); List<String> list2 = list.stream().distinct().collect(Collectors.toList()); // 收集成Set集合 Set<String> set1 = list.stream().distinct().collect(Collectors.toSet()); // 收集成Map集合。 List<Student> students = new ArrayList<>(); students.add(new Student("小明", 18, 90.0, "北京")); students.add(new Student("小红", 19, 80.0, "上海")); students.add(new Student("小刚", 20, 70.0, "广州")); students.add(new Student("小花", 21, 60.0, "深圳")); // 方式1:匿名内部类方式 Map<String, Double> map = students.stream().collect(Collectors.toMap( new Function<Student, String>() { @Override public String apply(Student student) { return student.getName(); } }, new Function<Student, Double>() { @Override public Double apply(Student student) { return student.getScore(); } } )); // 方式2:lambda方式 Map<String, Double> map2 = students.stream().collect(Collectors.toMap( student -> student.getName(), student->student.getScore() )); // 方式3(推荐):特殊方法引用方式(类名::实例方法,要求:传入的第一个参数是方法体内主调用方法参数,其他参数作为调用方法的参数) Map<String, Double> map3 = students.stream().collect(Collectors.toMap( Student::getName, //特殊类型方法引用: 代替的方法要求是第一个参数作为对象,调用getName方法 Student::getScore )); System.out.println(map3); } }