zoukankan      html  css  js  c++  java
  • 09_Java8操作集合的一些新特性

    【使用forEach()结合Lambda表达式遍历集合】

    public class ForEachDemo {
        public static void main(String[] args) {
            Collection<String> list=new ArrayList<>();
            list.add("Apple");
            list.add("Banana");
            list.add("Tomato");
         //调用forEach()方法来遍历集合 list.forEach(obj
    ->System.out.println(obj)); } }

    【关于forEach(Consumer action)方法】

      Java8为Iterable接口新增了一个forEach(Consumer action)默认方法,该方法的参数类型Consumer是一个函数式接口,而Iterable接口是Collection的父接口,因此Collection可以直接调用该方法。

      当程序调用Iterable的forEach(Consumer action)方法遍历集合元素时,程序会依次将集合元素传给Consumer的accept(T t)方法(该接口中唯一的抽象方法),Consumer是一个函数式接口,所以可以使用Lambda表达式来遍历集合元素。

    【Java8新增的Predicate操作集合】

    Java8为Collection集合新增了一个removeIf(Predicate filter)方法,该方法会删除符合filter条件的所有元素。

    该方法需要一个Predicate对象作为参数,Predicate也是函数式接口,因此可以使用Lambda表达式作为参数。

    package com.Hggin.ForEach;
    
    import java.util.ArrayList;
    import java.util.Collection;
    
    public class PredicateDemo {
        public static void main(String[] args) {
            Collection<String> books=new ArrayList<>();
            books.add("《Java编程思想》");
            books.add("《Java并发编程》");
            books.add("《Java多线程实战》");
            books.add("《Spring实战》");
            books.add("《Spring技术内幕》");
            books.add("《大话数据结构》");
            books.add("《大话设计模式》");
            books.add("《设计模式之禅》");
            
            /**
             * 使用Lambda表达式(目标类型是Predicate)过滤集合
             * 移除所有带"Java"字符串的集合元素
             */
            books.removeIf(book->((String)book).contains("Java")); 
            for(String b:books){
                System.out.println("-----"+b);
            } 
            
            /**
             * 使用Lambda表达式(目标类型是Predicate)过滤集合
             * 移除所有字符串以"《大话"开头的集合元素
             */
            books.removeIf(book->((String)book).startsWith("《大话"));
            for(String b:books){
                System.out.println("====="+b);
            }
            
        }
    }

    【运行结果】

    【分析】

    上面调用了Collection集合的removeIf()方法批量删除集合中符合条件的元素,程序传入一个Lambda表达式作为过滤条件:所有满足条件的元素都会被删除。

    【Predicate的test()方法的过滤统计作用】

    public static void main(String[] args) {
        Collection<String> books=new ArrayList<>();
        books.add("《Java编程思想》");
        books.add("《Java并发编程》");
        books.add("《Java多线程实战》");
        books.add("《Spring实战》");
        books.add("《Spring技术内幕》");
        books.add("《大话数据结构》");
        books.add("《大话设计模式》");
        books.add("《设计模式之禅》");
        books.add("《我是一个长度很长长长长长长长长长长长长长长长长长长的书名》");
        books.add("《我也是一个长度很长长长长长长长长长长长长长长长长长长的书名》");
        
        //统计含有"Spring"的子串的书名
        System.out.println(callAll(books,book->((String)book).contains("Spring")));
        
        //统计含有"Java"的子串的书名
        System.out.println(callAll(books,book->((String)book).contains("Java")));
        
        //统计
        System.out.println(callAll(books,book->((String)book).length()>15));
        
    }
    
    /**
     * 统计books集合中满足某个条件的集合元素的数量
     * 使用Predicate判断每个集合元素是否满足特定的条件
     * 该条件是通过Predicate参数动态传入 
     */
    public static int callAll(Collection books,Predicate p){
        int total=0;
        for(Object obj:books){
            if(p.test(obj)){  //只会统计满足条件的对象
                total++;
            }
        }
        return total;
    }

    【运行结果】

    【分析】

    Java8在java.util.function包下预定以的典型接口之一xxxPredicate接口,通常包含一个test()抽象方法,该方法常用于对参数进行某种判断(test()方法的判断逻辑由Lambda表达式的方式实现),然后返回一个boolean值。该Predicate函数式接口常用语判断参数是否满足特定条件,常用于数据的筛选。

    【Java8新增的流式API——Stream操作集合】

    Java8新增了Stream、IntStream、LongStream、DoubleStream等流式API,这些API代表多个支持串行和并行聚集操作的元素。

    Stream是一个通用的流接口,而IntStream、LongStream、DoubleStream则代表元素的类型为int、long、double的流。

    Java8还为每个流式API提供了对应的Builder,例如Stream.Builder、IntStream.Builder,可以使用这些Builder来创建对应的流。

    【独立使用Stream流的步骤】

    1.使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder。

    2.重复调用Builder的add()方法向该流中添加多个元素。

    3.调用Builder的build()方法获取对应的Stream。

    4.调用Stream的聚集方法。

    【关于聚集方法】

    上面第4步可以根据具体需求来调用不同的方法,Stream提供了大量的聚集方法供用户调用。

    注意:对于大部分聚集方法而言,每个Stream只能执行一次!!!

    【实例】

    public static void main(String[] args) {
        IntStream intS=IntStream.builder()
                        .add(8)
                        .add(18)
                        .add(-16)
                        .add(9)
                        .build();
        //下面调用聚集方法的代码每次只能执行一次,执行多个会报错!!!执行某个方法时记得注释其它方法!!
        System.out.println("intS流中所有元素的最大值:"+intS.max().getAsInt());     //18
        System.out.println("intS流中所有元素的最小值:"+intS.min().getAsInt());     //-16
        System.out.println("intS流中所有元素的总和:"+intS.sum());                //19
        System.out.println("intS流中所有元素的总数:"+intS.count());               //4
        System.out.println("intS流中所有元素的平均值:"+intS.average());            //OptionalDouble[4.75]      
        System.out.println("intS流中所有元素的平方是否都大于100:"+intS.allMatch(ele->ele*ele>100));    //false
        System.out.println("intS流中含有任何元素的平方是否大于100:"+intS.anyMatch(ele->ele*ele>100));  //true
        
        
        //将intS映射成一个新的Stream,新Stream的每个元素是原Stream每个元素+1
        IntStream newIntS=intS.map(ele->ele+1);
        //遍历集合元素:使用Lambda表达式的方式
        newIntS.forEach(ele->System.out.print("----"+ele));     //----9----19-----15----10
        //便利集合元素:使用方法引用
        newIntS.forEach(System.out::print);                     //919-1510
    }

    【聚集操作分类】

    [ 中间方法 ]

    中间操作允许流保持打开状态,并允许直接调用后续方法。上例中的map方法就是中间方法,中间方法的返回值是另外一个流。

    [ 末端方法 ]

    末端方法是对流的最终操作。当对某个Stream执行末端方法后,该流将会被"消耗",且不可再用。上例中的sum()、count().....大都是末端方法。

    【流的方法的两个特征】

    [ 有状态的方法 ]

    这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等。

    有状态的方法一般会需要更大的性能开销。

    [ 短路方法 ]

    短路方法会尽早结束对流的操作,不必检查所有的元素。

    【Stream常用的中间方法】

    * filter(Predicate predicate):过滤Stream中不符合predicate的元素。即保留满足条件的元素。

    * mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素。

    * peek(Cosumer action):依次对每个元素执行一些操作,该方法返回的流与原有的流包含相同的元素。该方法常用于调试。

    * distinct():该方法用于排序流中所有重复元素(判断元素重复的标准是使用equals()比较返回true)。这是一个有状态的方法。

    * sorted():该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法。

    * limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态、短路的方法。

    【Stream常用的末端方法】

    * forEach(Cosumer action):遍历流中的所有元素,对每个元素执行action。

    * toArray():将流中的所有元素转换成一个数组。

    * reduce():该方法有3个重载的版本,都用于通过某种操作来合并流中的元素。

    * min():返回流中的所有元素的最小值。

    * max():返回流中的所有元素的最大值。

    * count():返回流中所有元素的数量。

    * anyMatch(Predicate predicate):判断流中是否至少包含一个元素满足符合Predicate条件。

    * allMatch(Predicate predicate):判断流中是否每个元素都符合Predicate条件。

    * noneMatch(Predicate predicate):判断流中是否含有所有元素都不符合Predicate条件。

    * findFirst():返回流中的第一个元素。

    * findAny():返回流中的任意一个元素。

     【使用Stream直接对集合中的元素进行批量操作】

    public static void main(String[] args) {
         Collection<String> books=new ArrayList<>();
         books.add("《Java编程思想》");
         books.add("《Java并发编程》");
         books.add("《Java多线程实战》");
         books.add("《Spring实战》");
         books.add("《Spring技术内幕》");
         books.add("《大话数据结构》");
         books.add("《大话设计模式》");
         books.add("《设计模式之禅》");
         books.add("《我是一个长度很长长长长长长长长长长长长长长长长长长的书名》");
         books.add("《我也是一个长度很长长长长长长长长长长长长长长长长长长的书名》");    
         
         //统计包含"Java"的书本数量
         System.out.println(books.stream()
                                 .filter(ele->((String)ele).contains("Java"))
                                 .count());   //3
         //统计以"《大话"开头的书本数量
         System.out.println(books.stream()
                                 .filter(ele->((String)ele).startsWith("《大话"))
                                 .count());     //2
         //统计输名字长度大于15的数量
         System.out.println(books.stream()
                         .filter(ele->((String)ele).length()>15)
                             .count());    //2
         //先调用Collection对象的Stream()方法将集合转换成Stream对象
         //再调用Stream对象的maptoInt()方法获取原有的Stream对应的IntStream
       //这里的mapToInt是一个中间方法,因此程序可以继续调用IntStream的forEach方法来遍历流中的数据
    books.stream().mapToInt(ele->((String)ele).length()) .forEach(ele->System.out.print("--"+ele)); //--10--10--11--10--12--8--8--8--30--31 }

    【运行结果】

  • 相关阅读:
    Java 练习(经典例题: 生产者/消费者问题)
    Java 基础(线程的通信)
    Java 练习(线程的同步)
    Java 基础( ReentrantLock )
    Java 基础(线程的死锁问题)
    Java基础(单实例设计模式懒汉式解决线程安全)
    Java 基础(同步方法解决线程安全问题)
    Java 基础(Thread类的有关方法,线程的调度)
    Java 基础(线程的生命周期, 同步代码块解决线程安全)
    Java 基础(以实现 Runnable 接口的方式创建多线程)
  • 原文地址:https://www.cnblogs.com/HigginCui/p/6122642.html
Copyright © 2011-2022 走看看