编程语言如何巧用Java8中的Stream

    作者:坚持就是胜利更新于: 2020-01-31 15:36:43

    大神带你学编程,欢迎选课

    巧用Java8中的Stream,让集合操作6到飞起!

    编程语言往往使程序员能够比使用机器语言更准确地表达他们所想表达的目的。对那些从事计算机科学的人来说,懂得程序设计语言是十分重要的,因为在当今所有的计算都需要程序设计语言才能完成。

    简介

    java8也出来好久了,接口默认方法,lambda表达式,函数式接口,Date API等特性还是有必要去了解一下。比如在项目中经常用到集合,遍历集合可以试下lambda表达式,经常还要对集合进行过滤和排序,Stream就派上用场了。用习惯了,不得不说真的很好用。

    Stream作为java8的新特性,基于lambda表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。

    Stream的原理:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

    集合有两种方式生成流:

    • stream() − 为集合创建串行流
    • parallelStream() - 为集合创建并行流

    上图中是Stream类的类结构图,里面包含了大部分的中间和终止操作。

    中间操作主要有以下方法(此类型方法返回的都是Stream):map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

    终止操作主要有以下方法:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

    举例说明

    首先为了说明Stream对对象集合的操作,新建一个Student类(学生类),覆写了equals()和hashCode()方法

    1. public class Student { 
    2.  
    3.     private Long id; 
    4.  
    5.     private String name
    6.  
    7.     private int age; 
    8.  
    9.     private String address; 
    10.  
    11.     public Student() {} 
    12.  
    13.     public Student(Long id, String nameint age, String address) { 
    14.         this.id = id; 
    15.         this.name = name
    16.         this.age = age; 
    17.         this.address = address; 
    18.     } 
    19.  
    20.     @Override 
    21.     public String toString() { 
    22.         return "Student{" + 
    23.                 "id=" + id + 
    24.                 ", name='" + name + '\\'' + 
    25.                 ", age=" + age + 
    26.                 ", address='" + address + '\\'' + 
    27.                 '}'
    28.     } 
    29.  
    30.     @Override 
    31.     public boolean equals(Object o) { 
    32.         if (this == o) return true
    33.         if (o == null || getClass() != o.getClass()) return false
    34.         Student student = (Student) o; 
    35.         return age == student.age && 
    36.                 Objects.equals(id, student.id) && 
    37.                 Objects.equals(name, student.name) && 
    38.                 Objects.equals(address, student.address); 
    39.     } 
    40.  
    41.     @Override 
    42.     public int hashCode() { 
    43.         return Objects.hash(id, name, age, address); 
    44.     } 
    45.  
    46.     public Long getId() { 
    47.         return id; 
    48.     } 
    49.  
    50.     public void setId(Long id) { 
    51.         this.id = id; 
    52.     } 
    53.  
    54.     public String getName() { 
    55.         return name
    56.     } 
    57.  
    58.     public void setName(String name) { 
    59.         this.name = name
    60.     } 
    61.  
    62.     public int getAge() { 
    63.         return age; 
    64.     } 
    65.  
    66.     public void setAge(int age) { 
    67.         this.age = age; 
    68.     } 
    69.  
    70.     public String getAddress() { 
    71.         return address; 
    72.     } 
    73.  
    74.     public void setAddress(String address) { 
    75.         this.address = address; 
    76.     } 
    77.  

    filter(筛选)

    1. public static void main(String [] args) { 
    2.  
    3.         Student s1 = new Student(1L, "肖战", 15, "浙江"); 
    4.         Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    5.         Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    6.         Student s4 = new Student(4L, "李现", 17, "浙江"); 
    7.         List students = new ArrayList<>(); 
    8.         students.add(s1); 
    9.         students.add(s2); 
    10.         students.add(s3); 
    11.         students.add(s4); 
    12.  
    13.         List streamStudents = testFilter(students); 
    14.         streamStudents.forEach(System.out::println); 
    15.     } 
    16.     /** 
    17.      * 集合的筛选 
    18.      * @param students 
    19.      * @return 
    20.      */ 
    21.     private static List testFilter(List students) { 
    22.         //筛选年龄大于15岁的学生 
    23. //        return students.stream().filter(s -> s.getAge()>15).collect(Collectors.toList()); 
    24.         //筛选住在浙江省的学生 
    25.         return students.stream().filter(s ->"浙江".equals(s.getAddress())).collect(Collectors.toList()); 
    26.     } 

    运行结果:

    这里我们创建了四个学生,经过filter的筛选,筛选出地址是浙江的学生集合。

    map(转换)

    1. public static void main(String [] args) { 
    2.  
    3.        Student s1 = new Student(1L, "肖战", 15, "浙江"); 
    4.        Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    5.        Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    6.        Student s4 = new Student(4L, "李现", 17, "浙江"); 
    7.        List students = new ArrayList<>(); 
    8.        students.add(s1); 
    9.        students.add(s2); 
    10.        students.add(s3); 
    11.        students.add(s4); 
    12.  
    13.        testMap(students); 
    14.    } 
    15.  
    16.    /** 
    17.     * 集合转换 
    18.     * @param students 
    19.     * @return 
    20.     */ 
    21.    private static void testMap(List students) { 
    22.        //在地址前面加上部分信息,只获取地址输出 
    23.        List addresses = students.stream().map(s ->"住址:"+s.getAddress()).collect(Collectors.toList()); 
    24.        addresses.forEach(a ->System.out.println(a)); 
    25.    } 

    运行结果

    map就是将对应的元素按照给定的方法进行转换。

    distinct(去重)

    1. public static void main(String [] args) { 
    2.  
    3.      testDistinct1(); 
    4.    } 
    5.  
    6.    /** 
    7.     * 集合去重(基本类型) 
    8.     */ 
    9.    private static void testDistinct1() { 
    10.        //简单字符串的去重 
    11.        List list = Arrays.asList("111","222","333","111","222"); 
    12.        list.stream().distinct().forEach(System.out::println); 
    13.    } 

    运行结果:

    1. public static void main(String [] args) { 
    2.  
    3.       testDistinct2(); 
    4.     } 
    5.  
    6.     /** 
    7.      * 集合去重(引用对象) 
    8.      */ 
    9.     private static void testDistinct2() { 
    10.         //引用对象的去重,引用对象要实现hashCode和equal方法,否则去重无效 
    11.         Student s1 = new Student(1L, "肖战", 15, "浙江"); 
    12.         Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    13.         Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    14.         Student s4 = new Student(4L, "李现", 17, "浙江"); 
    15.         Student s5 = new Student(1L, "肖战", 15, "浙江"); 
    16.         List students = new ArrayList<>(); 
    17.         students.add(s1); 
    18.         students.add(s2); 
    19.         students.add(s3); 
    20.         students.add(s4); 
    21.         students.add(s5); 
    22.         students.stream().distinct().forEach(System.out::println); 
    23.     } 

    运行结果:

    可以看出,两个重复的“肖战”同学进行了去重,这不仅因为使用了distinct()方法,而且因为Student对象重写了equals和hashCode()方法,否则去重是无效的。

    sorted(排序)

    1. public static void main(String [] args) { 
    2.  
    3.       testSort1(); 
    4.   } 
    5.  
    6.   /** 
    7.    * 集合排序(默认排序) 
    8.    */ 
    9.   private static void testSort1() { 
    10.       List list = Arrays.asList("333","222","111"); 
    11.       list.stream().sorted().forEach(System.out::println); 
    12.   } 

    运行结果:

    1. public static void main(String [] args) { 
    2.  
    3.     testSort2(); 
    4.  
    5. /** 
    6.  * 集合排序(指定排序规则) 
    7.  */ 
    8. private static void testSort2() { 
    9.     Student s1 = new Student(1L, "肖战", 15, "浙江"); 
    10.     Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    11.     Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    12.     Student s4 = new Student(4L, "李现", 17, "浙江"); 
    13.     List students = new ArrayList<>(); 
    14.     students.add(s1); 
    15.     students.add(s2); 
    16.     students.add(s3); 
    17.     students.add(s4); 
    18.     students.stream() 
    19.             .sorted((stu1,stu2) ->Long.compare(stu2.getId(), stu1.getId())) 
    20.             .sorted((stu1,stu2) -> Integer.compare(stu2.getAge(),stu1.getAge())) 
    21.             .forEach(System.out::println); 

    运行结果:

    上面指定排序规则,先按照学生的id进行降序排序,再按照年龄进行降序排序

    limit(限制返回个数)

    1. public static void main(String [] args) { 
    2.  
    3.        testLimit(); 
    4.    } 
    5.  
    6.    /** 
    7.     * 集合limit,返回前几个元素 
    8.     */ 
    9.    private static void testLimit() { 
    10.        List list = Arrays.asList("333","222","111"); 
    11.        list.stream().limit(2).forEach(System.out::println); 
    12.    } 

    运行结果:

    skip(删除元素)

    1. public static void main(String [] args) { 
    2.  
    3.        testSkip(); 
    4.    } 
    5.  
    6.    /** 
    7.     * 集合skip,删除前n个元素 
    8.     */ 
    9.    private static void testSkip() { 
    10.        List list = Arrays.asList("333","222","111"); 
    11.        list.stream().skip(2).forEach(System.out::println); 
    12.    } 

    运行结果:

    reduce(聚合)

    1. public static void main(String [] args) { 
    2.         testReduce(); 
    3.     } 
    4.     /** 
    5.      * 集合reduce,将集合中每个元素聚合成一条数据 
    6.      */ 
    7.     private static void testReduce() { 
    8.         List list = Arrays.asList("欢","迎","你"); 
    9.         String appendStr = list.stream().reduce("北京",(a,b) -> a+b); 
    10.         System.out.println(appendStr); 
    11.     } 

    运行结果:

    min(求最小值)

    1. public static void main(String [] args) { 
    2.       testMin(); 
    3.   } 
    4.  
    5.   /** 
    6.    * 求集合中元素的最小值 
    7.    */ 
    8.   private static void testMin() { 
    9.       Student s1 = new Student(1L, "肖战", 14, "浙江"); 
    10.       Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    11.       Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    12.       Student s4 = new Student(4L, "李现", 17, "浙江"); 
    13.       List students = new ArrayList<>(); 
    14.       students.add(s1); 
    15.       students.add(s2); 
    16.       students.add(s3); 
    17.       students.add(s4); 
    18.       Student minS = students.stream().min((stu1,stu2) ->Integer.compare(stu1.getAge(),stu2.getAge())).get(); 
    19.       System.out.println(minS.toString()); 
    20.   } 

    运行结果:

    上面是求所有学生中年龄最小的一个,max同理,求最大值。

    anyMatch/allMatch/noneMatch(匹配)

    1. public static void main(String [] args) { 
    2.        testMatch(); 
    3.    } 
    4.  
    5.    private static void testMatch() { 
    6.        Student s1 = new Student(1L, "肖战", 15, "浙江"); 
    7.        Student s2 = new Student(2L, "王一博", 15, "湖北"); 
    8.        Student s3 = new Student(3L, "杨紫", 17, "北京"); 
    9.        Student s4 = new Student(4L, "李现", 17, "浙江"); 
    10.        List students = new ArrayList<>(); 
    11.        students.add(s1); 
    12.        students.add(s2); 
    13.        students.add(s3); 
    14.        students.add(s4); 
    15.        Boolean anyMatch = students.stream().anyMatch(s ->"湖北".equals(s.getAddress())); 
    16.        if (anyMatch) { 
    17.            System.out.println("有湖北人"); 
    18.        } 
    19.        Boolean allMatch = students.stream().allMatch(s -> s.getAge()>=15); 
    20.        if (allMatch) { 
    21.            System.out.println("所有学生都满15周岁"); 
    22.        } 
    23.        Boolean noneMatch = students.stream().noneMatch(s -> "杨洋".equals(s.getName())); 
    24.        if (noneMatch) { 
    25.            System.out.println("没有叫杨洋的同学"); 
    26.        } 
    27.    } 

    运行结果:

    anyMatch:Stream 中任意一个元素符合传入的 predicate,返回 true

    allMatch:Stream 中全部元素符合传入的 predicate,返回 true

    noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

    总结

    上面介绍了Stream常用的一些方法,虽然对集合的遍历和操作可以用以前常规的方式,但是当业务逻辑复杂的时候,你会发现代码量很多,可读性很差,明明一行代码解决的事情,你却写了好几行。试试lambda表达式,试试Stream,你会有不一样的体验。

    编程语言原本是被设计成专门使用在计算机上的,但它们也可以用来定义算法或者数据结构。正是因为如此,程序员才会试图使程序代码更容易阅读。

课课家教育

未登录