小工具知识网

当前位置: 首页 > 行业知识 > Stream流

行业知识

Stream流

2026-11-13 02:01:52 来源:互联网转载

1、体验Stream流【理解】

  • ���例需求

    按照下面的要求完成集合的创建和遍历

    • 创建一个集合,存储多个字符串元素

    • 把集合中所有以"张"开头的元素存储到一个新的集合

    • 把"张"开头的集合中的长度为3的元素存储到一个新的集合

    • 遍历上一步得到的集合

  • 原始方式示例代码

    public class MyStream1 {    public static void main(String[] args) {        //集合的批量添加        ArrayList list1 = new ArrayList(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));        //list.add()​        //遍历list1把以张开头的元素添加到list2中。        ArrayList list2 = new ArrayList();        for (String s : list1) {            if(s.startsWith("张")){                list2.add(s);            }        }        //遍历list2集合,把其中长度为3的元素,再添加到list3中。        ArrayList list3 = new ArrayList();        for (String s : list2) {            if(s.length() == 3){                list3.add(s);            }        }        for (String s : list3) {            System.out.println(s);        }          }}
  • 使用Stream流示例代码

    public class StreamDemo {    public static void main(String[] args) {        //集合的批量添加        ArrayList list1 = new ArrayList(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));​        //Stream流        list1.stream().filter(s->s.startsWith("张"))                .filter(s->s.length() == 3)                .forEach(s-> System.out.println(s));    }}
  • Stream流的好处

    • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印

    • Stream流把真正的函数式编程风格引入到Java中

    • 代码简洁

    1.1Stream流的常见生成方式【应用】

    • Stream流的思想

    • Stream流的三类方法

      • 获取Stream流

        • 创建一条流水线,并把数据放到流水线上准备进行操作

      • 中间方法

        • 流水线上的操作

        • 一次操作完毕之后,还可以继续进行其他操作

      • 终结方法

        • 一个Stream流只能有一个终结方法

        • 是流水线上的最后一个操作

    • 生成Stream流的方式

      • Collection体系集合

        使用默认方法stream()生成流, default Stream stream()

      • Map体系集合

        把Map转成Set集合,间接的生成流

      • 数组

        通过Arrays中的静态方法stream生成流

      • 同种数据类型的多个数据

        通过Stream接口的静态方法of(T... values)生成流

    • 代码演示

      public class StreamDemo {    public static void main(String[] args) {        //Collection体系的集合可以使用默认方法stream()生成流        List list = new ArrayList();        Stream listStream = list.stream();​        Set set = new HashSet();        Stream setStream = set.stream();​        //Map体系的集合间接的生成流        Map map = new HashMap();        Stream keyStream = map.keySet().stream();        Stream valueStream = map.values().stream();        Stream entryStream = map.entrySet().stream();​        //数组可以通过Arrays中的静态方法stream生成流        String[] strArray = {"hello","world","java"};        Stream strArrayStream = Arrays.stream(strArray);              //同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流        Stream strArrayStream2 = Stream.of("hello", "world", "java");        Stream intStream = Stream.of(10, 20, 30);    }}

      1.2Stream流中间操作方法【应用】

      • 概念

        中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

      • 常见方法

        方法名说明
        Stream filter(Predicate predicate)用于对流中的数据进行过滤
        Stream limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
        Stream skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
        static Stream concat(Stream a, Stream b)合并a和b两个流为一个流
        Stream distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
      • filter代码演示

        public class MyStream3 {    public static void main(String[] args) {//        Stream filter(Predicate predicate):过滤//        Predicate接口中的方法   boolean test(T t):对给定的参数进行判断,返回一个布尔值​        ArrayList list = new ArrayList();        list.add("张三丰");        list.add("张无忌");        list.add("张翠山");        list.add("王二麻子");        list.add("张良");        list.add("谢广坤");​        //filter方法获取流中的 每一个数据.        //而test方法中的s,就依次表示流中的每一个数据.        //我们只要在test方法中对s进行判断就可以了.        //如果判断的结果为true,则当前的数据留下        //如果判断的结果为false,则当前数据就不要.//        list.stream().filter(//                new Predicate() {//                    @Override//                    public boolean test(String s) {//                        boolean result = s.startsWith("张");//                        return result;//                    }//                }//        ).forEach(s-> System.out.println(s));​        //因为Predicate接口中只有一个抽象方法test        //所以我们可以使用lambda表达式来简化//        list.stream().filter(//                (String s)->{//                    boolean result = s.startsWith("张");//                        return result;//                }//        ).forEach(s-> System.out.println(s));​        list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));​    }}
      • limit&skip代码演示

        public class StreamDemo02 {    public static void main(String[] args) {        //创建一个集合,存储多个字符串元素        ArrayList list = new ArrayList();​        list.add("林青霞");        list.add("张曼玉");        list.add("王祖贤");        list.add("柳岩");        list.add("张敏");        list.add("张无忌");​        //需求1:取前3个数据在控制台输出        list.stream().limit(3).forEach(s-> System.out.println(s));        System.out.println("--------");​        //需求2:跳过3个元素,把剩下的元素在控制台输出        list.stream().skip(3).forEach(s-> System.out.println(s));        System.out.println("--------");​        //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出        list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));    }}
      • concat&distinct代码演示

        public class StreamDemo03 {    public static void main(String[] args) {        //创建一个集合,存储多个字符串元素        ArrayList list = new ArrayList();​        list.add("林青霞");        list.add("张曼玉");        list.add("王祖贤");        list.add("柳岩");        list.add("张敏");        list.add("张无忌");​        //需求1:取前4个数据组成一个流        Stream s1 = list.stream().limit(4);​        //需求2:跳过2个数据组成一个流        Stream s2 = list.stream().skip(2);​        //需求3:合并需求1和需求2得到的流,并把结果在控制台输出//        Stream.concat(s1,s2).forEach(s-> System.out.println(s));​        //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复        Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));    }}

        1.3Stream流终结操作方法【应用】

        • 概念

          终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

        • 常见方法

          方法名说明
          void forEach(Consumer action)对此流的每个元素执行操作
          long count()返回此流中的元素数
        • 代码演示

          public class MyStream5 {    public static void main(String[] args) {        ArrayList list = new ArrayList();        list.add("张三丰");        list.add("张无忌");        list.add("张翠山");        list.add("王二麻子");        list.add("张良");        list.add("谢广坤");​        //method1(list);        //        long count():返回此流中的元素数        long count = list.stream().count();        System.out.println(count);    }​    private static void method1(ArrayList list) {        //  void forEach(Consumer action):对此流的每个元素执行操作        //  Consumer接口中的方法void accept(T t):对给定的参数执行此操作        //在forEach方法的底层,会循环获取到流中的每一个数据.        //并循环调用accept方法,并把每一个数据传递给accept方法        //s就依次表示了流中的每一个数据.        //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.        list.stream().forEach(                new Consumer() {                    @Override                    public void accept(String s) {                        System.out.println(s);                    }                }        );              System.out.println("====================");        //lambda表达式的简化格式        //是因为Consumer接口中,只有一个accept方法        list.stream().forEach(                (String s)->{                    System.out.println(s);                }        );        System.out.println("====================");        //lambda表达式还是可以进一步简化的.        list.stream().forEach(s->System.out.println(s));    }}

          1.4Stream流的收集操作【应用】

          • 概念

            对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

          • 常用方法

            方法名说明
            R collect(Collector collector)把结果收集到集合中
          • 工具类Collectors提供了具体的收集方式

            方法名说明
            public static Collector toList()把元素收集到List集合中
            public static Collector toSet()把元素收集到Set集合中
            public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
          • 代码演示

            // toList和toSet方法演示 public class MyStream7 {    public static void main(String[] args) {        ArrayList list1 = new ArrayList();        for (int i = 1; i  number % 2 == 0)                .collect(Collectors.toList());​        System.out.println(list);​    Set set = list1.stream().filter(number -> number % 2 == 0)            .collect(Collectors.toSet());    System.out.println(set);}}/**Stream流的收集方法 toMap方法演示创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄"zhangsan,23""lisi,24""wangwu,25"保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值*/public class MyStream8 {    public static void main(String[] args) {        ArrayList list = new ArrayList();        list.add("zhangsan,23");        list.add("lisi,24");        list.add("wangwu,25");​        Map map = list.stream().filter(                s -> {                    String[] split = s.split(",");                    int age = Integer.parseInt(split[1]);                    return age >= 24;                }​         //   collect方法只能获取到流中剩余的每一个数据.         //在底层不能创建容器,也不能把数据添加到容器当中​         //Collectors.toMap 创建一个map集合并将数据添加到集合当中​          // s 依次表示流中的每一个数据​          //第一个lambda表达式就是如何获取到Map中的键          //第二个lambda表达式就是如何获取Map中的值        ).collect(Collectors.toMap(                s -> s.split(",")[0],                s -> Integer.parseInt(s.split(",")[1]) ));​        System.out.println(map);    }}

            1.5Stream流综合练习【应用】

            • 案例需求

              现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

              • 男演员只要名字为3个字的前三人

              • 女演员只要姓林的,并且不要第一个

              • 把过滤后的男演员姓名和女演员姓名合并到一起

              • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

              演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

            • 代码实现

              演员类

              public class Actor {    private String name;​    public Actor(String name) {        this.name = name;    }​    public String getName() {        return name;    }​    public void setName(String name) {        this.name = name;    }}

              测试类

              public class StreamTest {    public static void main(String[] args) {        //创建集合        ArrayList manList = new ArrayList();        manList.add("周润发");        manList.add("成龙");        manList.add("刘德华");        manList.add("吴京");        manList.add("周星驰");        manList.add("李连杰");          ArrayList womanList = new ArrayList();        womanList.add("林心如");        womanList.add("张曼玉");        womanList.add("林青霞");        womanList.add("柳岩");        womanList.add("林志玲");        womanList.add("王祖贤");          //男演员只要名字为3个字的前三人        Stream manStream = manList.stream().filter(s -> s.length() == 3).limit(3);          //女演员只要姓林的,并且不要第一个        Stream womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);          //把过滤后的男演员姓名和女演员姓名合并到一起        Stream stream = Stream.concat(manStream, womanStream);          // 将流中的数据封装成Actor对象之后打印        stream.forEach(name -> {            Actor actor = new Actor(name);            System.out.println(actor);        });     }}

              2、方法引用

              2.1体验方法引用【理解】

              • 方法引用的出现原因

                在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作

                那么考虑一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑呢?答案肯定是没有必要

                那我们又是如何使用已经存在的方案的呢?

                这就是我们要讲解的方法引用,我们是通过方法引用来使用已经存在的方案

              • 代码演示

                public interface Printable {    void printString(String s);}​public class PrintableDemo {    public static void main(String[] args) {        //在主方法中调用usePrintable方法//        usePrintable((String s) -> {//            System.out.println(s);//        });        //Lambda简化写法        usePrintable(s -> System.out.println(s));​        //方法引用        usePrintable(System.out::println);​    }​    private static void usePrintable(Printable p) {        p.printString("爱生活爱Java");    }}
                ​

                2.2方法引用符【理解】

                • 方法引用符

                  :: 该符号为引用运算符,而它所在的表达式被称为方法引用

                • 推导与省略

                  • 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导

                  • 如果使用方法引用,也是同样可以根据上下文进行推导

                  • 方法引用是Lambda的孪生兄弟

                  2.3引用类方法【应用】

                  引用类方法,其实就是引用类的静态方法

                  • 格式

                    类名::静态方法

                  • 范例

                    Integer::parseInt

                    Integer类的方法:public static int parseInt(String s) 将此String转换为int类型数据

                  • 练习描述

                    • 定义一个接口(Converter),里面定义一个抽象方法 int convert(String s);

                    • 定义一个测试类(ConverterDemo),在测试类中提供两个方法

                      • 一个方法是:useConverter(Converter c)

                      • 一个方法是主方法,在主方法中调用useConverter方法

                  • 代码演示

                    public interface Converter {    int convert(String s);}​public class ConverterDemo {    public static void main(String[] args) {​        //Lambda写法        useConverter(s -> Integer.parseInt(s));​        //引用类方法        useConverter(Integer::parseInt);​    }​    private static void useConverter(Converter c) {        int number = c.convert("666");        System.out.println(number);    }}
                  • 使用说明

                    Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数

                    2.4引用对象的实例方法【应用】

                    引用对象的实例方法,其实就引用类中的成员方法

                    • 格式

                      对象::成员方法

                    • 范例

                      "HelloWorld"::toUpperCase

                      String类中的方法:public String toUpperCase() 将此String所有字符转换为大写

                    • 练习描述

                      • 定义一个类(PrintString),里面定义一个方法

                        public void printUpper(String s):把字符串参数变成大写的数据,然后在控制台输出

                      • 定义一个接口(Printer),里面定义一个抽象方法

                        void printUpperCase(String s)

                      • 定义一个测试类(PrinterDemo),在测试类中提供两个方法

                        • 一个方法是:usePrinter(Printer p)

                        • 一个方法是主方法,在主方法中调用usePrinter方法

                    • 代码演示

                      public class PrintString {    //把字符串参数变成大写的数据,然后在控制台输出    public void printUpper(String s) {        String result = s.toUpperCase();        System.out.println(result);    }}​public interface Printer {    void printUpperCase(String s);}​public class PrinterDemo {    public static void main(String[] args) {​        //Lambda简化写法        usePrinter(s -> System.out.println(s.toUpperCase()));​        //引用对象的实例方法        PrintString ps = new PrintString();        usePrinter(ps::printUpper);​    }​    private static void usePrinter(Printer p) {        p.printUpperCase("HelloWorld");    }}
                      ​
                    • 使用说明

                      Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数

                      2.5引用类的实例方法【应用】

                      引用类的实例方法,其实就是引用类中的成员方法

                      • 格式

                        类名::成员方法

                      • 范例

                        String::substring

                        public String substring(int beginIndex,int endIndex)

                        从beginIndex开始到endIndex结束,截取字符串。返回一个子串,子串的长度为endIndex-beginIndex

                      • 练习描述

                        • 定义一个接口(MyString),里面定义一个抽象方法:

                          String mySubString(String s,int x,int y);

                        • 定义一个测试类(MyStringDemo),在测试类中提供两个方法

                          • 一个方法是:useMyString(MyString my)

                          • 一个方法是主方法,在主方法中调用useMyString方法

                      • 代码演示

                        public interface MyString {    String mySubString(String s,int x,int y);}​public class MyStringDemo {    public static void main(String[] args) {        //Lambda简化写法        useMyString((s,x,y) -> s.substring(x,y));​        //引用类的实例方法        useMyString(String::substring);​    }​    private static void useMyString(MyString my) {        String s = my.mySubString("HelloWorld", 2, 5);        System.out.println(s);    }}
                      • 使用说明

                        Lambda表达式被类的实例方法替代的时候 ​ 第一个参数作为调用者 ​ 后面的参数全部传递给该方法作为参数

                        2.6引用构造器【应用】

                        引用构造器,其实就是引用构造方法

                        • l格式

                          类名::new

                        • 范例

                          Student::new

                        • 练习描述

                          • 定义一个类(Student),里面有两个成员变量(name,age)

                            并提供无参构造方法和带参构造方法,以及成员变量对应的get和set方法

                          • 定义一个接口(StudentBuilder),里面定义一个抽象方法

                            Student build(String name,int age);

                          • 定义一个测试类(StudentDemo),在测试类中提供两个方法

                            • 一个方法是:useStudentBuilder(StudentBuilder s)

                            • 一个方法是主方法,在主方法中调用useStudentBuilder方法

                        • 代码演示

                          public class Student {    private String name;    private 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;    }}​public interface StudentBuilder {    Student build(String name,int age);}​public class StudentDemo {    public static void main(String[] args) {​        //Lambda简化写法        useStudentBuilder((name,age) -> new Student(name,age));​        //引用构造器        useStudentBuilder(Student::new);​    }​    private static void useStudentBuilder(StudentBuilder sb) {        Student s = sb.build("林青霞", 30);        System.out.println(s.getName() + "," + s.getAge());    }}
                        • 使用说明

                          Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数

上一篇:手机旺旺服务器在哪里?

下一篇:怎么找网络的服务器号?