欢迎光临
我们一直在努力

Stream流全面讲解(流的思想,获取流,中间方法,终结方法等等,包含综合对应练习题)

(1)Stream流的思想和获取Stream流

Stream流的思想

流水线思想,java.util.stream.Stream<T> 是函数式接口,Stream本身是接口。

Stream流的作用

结合了Lambda表达式,简化集合、数组的操作

Stream流的使用步骤:
  • 先得到一条Stream流(流水线),并把数据放上去

  • 利用Stream流中的API进行各种操作(

  • 过滤,转换 -> 中间方法。 方法调用完毕之后,还可以调用其他方法

    统计,打印 -> 终结方法) 最后一步,调用完毕之后,不能调用其他方法

    所以:

  • 先得到一条Stream流(流水线),并把数据放上去

  • 使用中间方法对流水线上的数据进行操作

  • 使用终结方法对流水线上的数据进行操作

  • 获取Stream流的方式

    单列集合 default Stream<E> stream() Collection中的默认方法

    双列集合 无 无法直接使用stream流

    数组 public static<T> Stream<T> stream(T[] array) Arrays工具类中的静态方法

    一堆零散数据 public static<T> Stream<T> of(T…values) Stream接口中的静态方法

    细节:
    • 单列集合通过Collection中的默认方法stream()方法获取Stream流

    • 双列集合无法直接获取,需通过keySet()方法或者entrySet()方法获取对应的单列Set集合,然后调用单列集合中的stream方法

    • 数组可以通过Arrays工具类中的静态方法stream(T[] array)获取stream流

    • 一堆零散的数据,注意这些数据的数据类型一致,可以通过Stream接口中的of方法获取stream流

    这里Stream接口中静态方法of(T…values)方法的细节

    //方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组

    //但是数组必须是引用数据类型的,如果传递基本数据类型,则会把整个数组当做一个元素,放到Stream当中,打印时会打印该数组的地址。

    import java.util.*;
    import java.util.function.BiConsumer;
    import java.util.function.Consumer;
    import java.util.stream.Stream;

    public class StreamDemo1 {
    public static void main(String[] args) {
    //单列集合通过stream()方法获取Stream流
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"a","b","c","d","e");
    Stream<String> stream1 = list.stream();
    stream1.forEach(s->System.out.println(s));

    //双列集合无法直接获取
    HashMap<String, Integer> hm = new HashMap<>();
    hm.put("aaa",111);
    hm.put("bbb",222);
    hm.put("ccc",333);
    hm.put("ddd",444);
    //第一种获取stream流的方式Set<String>存储键的Set集合
    hm.keySet().stream().forEach(key->System.out.println(key));
    //第二种获取stream流的方式
    hm.entrySet().stream().forEach(entry->System.out.println(entry.getKey()+":"+entry.getValue()));
    // hm.entrySet().stream().forEach(new Consumer<Map.Entry<String, Integer>>() {
    // @Override
    // public void accept(Map.Entry<String, Integer> entry) {
    // System.out.println(entry.getKey()+":"+entry.getValue());
    // }
    // });

    //数组获取stream流的方式通过Arrays工具类中的静态方法stream(T[] array)方法获取
    int[] arr1 = {1,2,3,4,5};
    Arrays.stream(arr1).forEach(i->System.out.println(i));
    String[] arr2 = {"a","b","c","d","e"};
    Arrays.stream(arr2).forEach(s->System.out.println(s));

    //一堆零散的数据获取stream流,只不过这些零散的数据类型相同,通过Stream接口中的静态方法of(T…values);获取
    Stream.of(1,2,3,4).forEach(i->System.out.println(i));
    Stream.of("a","b","c","d","e").forEach(s->System.out.println(s));
    }
    }

    (2)Stream流的中间方法

    中间方法

    Stream<T> filter(Predicate<? super T> predicate) 过滤

    Stream<T> limit(long maxSize) 获取前几个元素

    Stream<T> skip(long n) 跳过前几个元素

    Stream<T> distinct() 元素去重,依赖(hashCode和equals方法)

    static <T>Stream<T> concat(Stream a,Stream b) 合并a和b两个流为一个流

    Stream<R> map(Function<T ,R> mapper) 转换流中的数据类型

    注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次(再次使用会出现IllegalStateException异常),建议使用链式编程

    注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据

    1、过滤

    filter里面的参数 Predicate是一个函数式接口,所以要实现里面的public boolean test(T a) {}方法

    例 public boolean test(String s){return s.startsWith("张");}

    //如果返回值为true,表示当前数据留下

    //如果返回值为false,表示当前数据舍弃不要

    2、元素去重

    distinct()底层是依赖HashSet,所以依赖hashCode和equals方法,如果泛型类型是自定义对象,那么需要在自定义类中进行重写方法。

    3、转换流中的数据类型

    map参数类型为函数式接口类型(Function),需要实现类实现该接口,然后通过new 这个实现类传递参数,但是JDK8以后的匿名内部类实现了这一复杂过程的简化,之后的Lambda表达式再次简化匿名内部类的书写

    例://Function函数式接口,泛型约束的类型,第一个类型:流中原本的数据类型,第二个类型:要转成之后的类型 //apply返回值:表示转换之后的数据 //当map方法执行完毕之后,流上的数据就变成了整数

    list4.stream().map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
    String[] arr = s.split("-");
    String ageString = arr[1];
    int age = Integer.parseInt(ageString);
    return age;
    }
    }).forEach(age-> System.out.println(age));

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.function.Function;
    import java.util.function.Predicate;
    import java.util.stream.Stream;

    public class StreamDemo2 {
    public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"刘备","孙尚香","孙权","孙策","孙仲谋","孙膑","马超");
    //filter过滤,参数为函数式接口对象,返回值为true保留,返回值为false不保留
    list.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
    return s.startsWith("孙");
    }
    }).forEach(s->System.out.println(s));

    Stream<String> stream1=list.stream().filter(s->s.startsWith("孙"));
    Stream<String> stream2=stream1.filter(s->s.length() == 3);
    stream2.forEach(s->System.out.println(s));
    System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
    //Stream<String> stream3 = stream1.filter(s->s.length()==3);

    list.stream().filter(s->s.startsWith("孙")).filter(s->s.length() == 3).forEach(s->System.out.println(s));
    //limit(int n)获取流中前n个元素
    list.stream().limit(3).forEach(s->System.out.println(s));
    System.out.println("+++++++++++++++++++++++++++++++++");
    //skip(int n)跳过lq中前n个元素
    list.stream().skip(4).forEach(s->System.out.println(s));
    System.out.println("+++++++++++++++++++++++++++++++++++");
    list.stream().limit(5).skip(2).forEach(s->System.out.println(s));

    ArrayList<String> list1 = new ArrayList<>();
    Collections.addAll(list1,"孙尚香","孙权","孙策","孙仲谋","孙膑","孙权","孙尚香");
    ArrayList<String> list2 = new ArrayList<>();
    Collections.addAll(list2,"刘备","张飞","关羽");
    //distinct 元素去重,依赖(hashCode和equals方法);
    list1.stream().distinct().forEach(s->System.out.println(s));
    System.out.println("+++++++++++++++++++++++++++++");
    //Stream接口中的静态方法concat,合并两个stream流
    Stream.concat(list1.stream(),list2.stream()).forEach(s->System.out.println(s));

    ArrayList<String> list4 = new ArrayList<>();
    Collections.addAll(list4,"刘备-32","孙尚香-18","孙权-19","孙策-28","孙仲谋-47","孙膑-81","马超-24");
    //Function函数式接口,泛型约束的类型,第一个类型:流中原本的数据类型,
    第二个类型:要转成之后的类型
    //apply返回值:表示转换之后的数据
    //当map方法执行完毕之后,流上的数据就变成了整数
    list4.stream().map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
    String[] arr = s.split("-");
    String ageString = arr[1];
    int age = Integer.parseInt(ageString);
    return age;
    }
    }).forEach(age-> System.out.println(age));
    }
    }

    (3)Stream流的终结方法

    终结方法

    void forEach(Consumer action) 遍历

    Long count() 统计

    toArray() 收集流中的数据,放到数组中

    collect(Collector collector) 收集流中的数据,放到集合中

    ——1、收集流中的数据,放到数组中

    String[] arr = list.stream().toArray(new IntFunction<String[]>() { @Override public String[] apply(int value) { return new String[value]; } }); System.out.println(Arrays.toString(arr));

    //有参 //IntFunction的泛型:具体类型的数组 //apply的形参:流中数据的个数,要跟数组的长度保持一致 //apply的返回值:具体类型的数组 //方法体:就是创建数组 //toArray方法的参数的作用:负责创建一个指定类型的数组 //toArray方法的底层,会依次得到流里面的每个数据,并把数据放到数组当中 //toArray方法的返回值:是一个装着流里面所有数据的数组

    toArray()方法引用:toArray(Integer[] :: new);

    方法引用:引用数组的构造方法

    格式:数据类型[]::new

    范例:int[]::new

    引用数组的构造方法就是为了创建数组。

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.function.Consumer;
    import java.util.function.IntFunction;

    public class StreamDemo3 {
    public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"刘备","孙尚香","孙权","孙策","孙仲谋","孙膑","马超");

    list.stream().forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
    System.out.println(s);
    }
    });

    //统计 long count()
    long count=list.stream().count();
    System.out.println(count);

    //toArray() 收集流里面的数据,把收集到的数据放到数组中
    //无参
    Object[] arr1 = list.stream().toArray();
    System.out.println(Arrays.toString(arr1));
    //有参
    //IntFunction的泛型:具体类型的数组
    //apply的形参:流中数据的个数,要跟数组的长度保持一致
    //apply的返回值:具体类型的数组
    //方法体:就是创建数组

    //toArray方法的参数的作用:负责创建一个指定类型的数组
    //toArray方法的底层,会依次得到流里面的每个数据,并把数据放到数组当中
    //toArray方法的返回值:是一个装着流里面所有数据的数组
    String[] arr = list.stream().toArray(new IntFunction<String[]>() {
    @Override
    public String[] apply(int value) {
    return new String[value];
    }
    });
    System.out.println(Arrays.toString(arr));

    String[] arr2 = list.stream().toArray( value-> new String[value]);
    System.out.println(Arrays.toString(arr2));
    }
    }

    ——2、收集流中的数据,放到集合中

    collect(Collector collector) 收集流中的数据,放到集合中(List Set Map)

    Collectors 是 java.util.stream 包下的一个工具类,全称java.util.stream.Collectors。

    它是一个工具类,里面全是静态方法,专门用来配合 Stream.collect() 做收集操作。

    常用的静态方法有:

    • Collectors.toList():收集为 List

    • Collectors.toSet():收集为 Set

    • Collectors.toMap():收集为 Map

    toMap的两个参数为Function函数式接口对象参数一表示键的生成规则,参数二表示值的生成规则,具体看下面的代码及详解

    import java.util.*;
    import java.util.function.Function;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;

    public class StreamDemo4 {
    public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,
    "张无忌-男-15",
    "周芷若-女-14",
    "赵敏-女-13",
    "张强-男-20",
    "张三丰-男-100",
    "张翠山-男-40",
    "张良-男-35",
    "王二麻子-男-37",
    "谢广坤-男-41"
    );
    //收集List集合道中,把所有的男性收集起来。
    List<String> newList1 = list.stream().filter(new Predicate<String>(){
    @Override
    public boolean test(String s) {
    return "男".equals(s.split("-")[1]);
    }
    }).collect(Collectors.toList());
    System.out.println(newList1);

    List<String> newList11 = list.stream()
    .filter( s-> "男".equals(s.split("-")[1]))
    .collect(Collectors.toList());

    //收集到Set集合当中,把所有男生
    Set<String> newList2 = list.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
    return "男".equals(s.split("-")[1]);
    }
    }).collect(Collectors.toSet());
    System.out.println(newList2);
    Set<String> newList22 = list.stream()
    .filter( s-> "男".equals(s.split("-")[1]))
    .collect(Collectors.toSet());

    //收集到Map集合中,把所有的男生收集起来,键:姓名,值:年龄
    /*toMap : 参数一表示键的生成规则
    参数二表示值的生成规则
    参数一:
    Function泛型一:表示流中每一个数据的类型
    泛型二:表示Map集合中键的数据类型
    方法apply形参:依次表示流里面的每一个数据
    方法体:生成键的代码
    返回值:已经生成的键
    参数二:
    Function泛型一:表示流中的每一个数据的类型
    泛型二:表示Map集合中值的数据类型
    方法apply形参:依次表示流里面的每一个数据
    方法体:生成值的代码
    返回值:已经生成的值
    */
    Map<String,Integer> m = list.stream().filter(s->"男".equals(s.split("-")[1]))
    .collect(Collectors.toMap(new Function<String,String>() {
    @Override
    public String apply(String s) {
    return s.split("-")[0];
    }
    }, new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
    return Integer.parseInt(s.split("-")[2]);
    }
    }
    ));
    System.out.println(m);

    Map<String,Integer> m1 = list.stream()
    .filter(s->"男".equals(s.split("-")[1]))
    .collect(Collectors.toMap(
    s-> s.split("-")[0],
    s-> Integer.parseInt(s.split("-")[2])));

    }
    }

    (4)Stream流总结

    (5)Stream流练习

    ——1、数字的过滤

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.function.Predicate;

    public class StreamDemo5{
    public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);

    list.stream().filter(new Predicate<Integer>() {
    @Override
    public boolean test(Integer n) {
    return n % 2 == 0 ? false : true;
    }
    }).forEach(i -> System.out.println(i));

    list.stream()
    .filter(n-> n % 2 == 0 ? false : true)
    .forEach(i -> System.out.println(i));
    }
    }

    ——2、字符串过滤并收集

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Map;
    import java.util.function.Function;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;

    public class StreamDemo6 {
    public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();

    Collections.addAll(list,"孙权,23","孙尚香,19","孙膑,81","孙策,35","孙仲谋,51","马超,23","周瑜,32","瑶,18");

    Map<String, Integer> map = list.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
    String ageStr = s.split(",")[1];
    Integer age = Integer.parseInt(ageStr);
    return age >=24;
    }
    }).collect(Collectors.toMap(new Function<String, String>() {
    @Override
    public String apply(String s) {
    return s.split(",")[0];
    }
    },new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
    return Integer.parseInt(s.split(",")[1]);
    }
    }));
    System.out.println(map);

    Map<String, Integer> m = list.stream()
    .filter( s-> {return Integer.parseInt(s.split(",")[1]) >=24; })
    .collect(Collectors.toMap(s-> s.split(",")[0],
    s-> Integer.parseInt(s.split(",")[1])));
    }
    }

    ——3、自定义对象的过滤收集

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.function.Function;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;

    public class StreamDemo7 {
    public static void main(String[] args) {
    ArrayList<String> list1 = new ArrayList<>();
    Collections.addAll(list1,"马超-23","赵子龙-29","关羽-40","张飞-38","曹操-43","牢大-35");
    ArrayList<String> list2 = new ArrayList<>();
    Collections.addAll(list2,"孙尚香-19","瑶-16","孙美姬-23","王昭君-25","杨玉环-31","孙樱-20");

    Stream<String> stream1 = list1.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
    return s.split("-")[0].length()==2;
    }
    }).limit(2);

    Stream<String> stream2 = list2.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
    return s.split("-")[0].startsWith("孙");
    }
    }).skip(1);

    List<Student> list = Stream.concat(stream1,stream2).map(new Function<String, Student>() {
    @Override
    public Student apply(String s) {
    Student stu = new Student();
    stu.setName(s.split("-")[0]);
    stu.setAge(Integer.parseInt(s.split("-")[1]));
    return stu;
    }
    }).collect(Collectors.toList());

    System.out.println(list);
    }
    }
    class Student {
    String name;
    int age;

    public Student() {}
    public Student(String name, int age) {
    this.name = name;
    this.age = age;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }

    @Override
    public String toString() {
    return "Student [name=" + name + ", age=" + age + "]";
    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » Stream流全面讲解(流的思想,获取流,中间方法,终结方法等等,包含综合对应练习题)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址