Java—Java 8 新增特性詳解(Predicate和Stream)

Predicate接口

Predicate接口介紹

??Predicate是函數式接口,可以使用Lambda表達式作為參數。Java 8為集合Collection新增了removeIf(Predicate filter)方法,可以批量刪除符合filter條件的所有元素。

Predicate接口使用范例

測試Collection的removeIf()方法。
示例1
1)運行類:

public class DemoApplication {

    public static void main(String[] args) {

        // 創建集合
        Collection collection = new HashSet();

        // 添加元素
        collection.add("book01");
        collection.add("book02");
        collection.add("book03");
        collection.add("b05");
        collection.add("b06");

        Collection collectionNew = new HashSet();
        // 使用Lambda表達式遍歷傳入新的集合
        collection.forEach(str -> collectionNew.add(str));
        System.out.println("collectionNew: " + collectionNew);

        // 使用Lambda表達式進行過濾(目標類型是Predicate)
        collection.removeIf(filter -> ((String)filter).length() < 5);

        // 使用Lambda表達式遍歷打印
        collection.forEach(str -> System.out.println(str));

        
        }
}

2)運行結果:

collectionNew: [book02, book01, b05, book03, b06]
book02
book01
book03

??從上述結果中,我們可以看到調用Collection集合的removeIf()方法,可以批量過濾符合條件長度小于5的集合元素,程序是傳入一個Lambda表達式進行過濾:collection.removeIf(filter -> ((String)filter).length() < 5);

示例2
使用Predicate接口的boolean test(T t);方法
1)創建工具類:

import java.util.Collection;
import java.util.function.Predicate;

/**
 * @author andya
 * @create 2020-03-24 14:08
 */
public class PredicateUtil {
    public static int countCollectionElement(Collection collection, Predicate predicate){
        int total = 0;
        for (Object object : collection) {
            //通過Predicate的test()方法判斷對象是否滿足過濾條件
            if (predicate.test(object)) {
                total ++;
            }
        }

        return total;
    }
}

2)運行類:

public class DemoApplication {

    public static void main(String[] args) {

        // 創建集合
        Collection collection = new HashSet();

        // 添加元素
        collection.add("book_java編程思想");
        collection.add("book_c++核心技術");
        collection.add("book_java核心技術");
        collection.add("book_計算機網絡");
        collection.add("book01");
        collection.add("book02");

        Collection collectionNew = new HashSet();
        // 使用Lambda表達式遍歷傳入新的集合
        collection.forEach(str -> collectionNew.add(str));
        System.out.println("collectionNew: " + collectionNew);

        System.out.println("包含java關鍵字的個數:" +
                PredicateUtil.countCollectionElement(collection, ele -> ((String)ele).contains("java")));
        System.out.println("長度小于7的個數:" +
                PredicateUtil.countCollectionElement(collection, ele -> ((String)ele).length() < 7));
        System.out.println("以book_為前綴的個數:" +
                PredicateUtil.countCollectionElement(collection, ele -> ((String)ele).startsWith("book_")));
        }
}

3)運行結果:

collectionNew: [book02, book01, book_java編程思想, book_java核心技術, book_計算機網絡, book_c++核心技術]
包含java關鍵字的個數:2
長度小于7的個數:2
以book_為前綴的個數:4

??定義了一個countCollectionElement()方法,使用Predicate動態傳參,判斷每個集合元素是否符合過濾條件。

Stream流式接口

Stream流式接口介紹

??Java 8新特性中還增加了流式處理,如Stream,IntStream,DoubleStream,LongStream等API。每個流式API還提供了對應的Builder,如Stream.Builder、IntStream.Builder、DoubleStream.Builder、LongStream.Builder。

Stream使用步驟

  1. 通過Stream等API的builder()類方法去創建Stream對應的Builder類;
  2. 調用Builder的add()方法向流中添加多個元素;
  3. 調用Builder的build()方法獲取對應的Stream;
  4. 調用Stream聚集方法;

Stream使用示例

public class DemoApplication {

    public static void main(String[] args) {

        //通過xxxStream的builder()方法去創建Builder
        IntStream intStream = IntStream.builder()
                .add(1)
                .add(-2)
                .add(3)
                .add(10)
                .build();

        // 聚集方法(每次只能使用其中一條去執行,其他代碼需注釋,否則會報錯)
        System.out.println("intStream的元素最大值是: " + intStream.max().getAsInt());
        System.out.println("intStream的元素最小值是: " + intStream.min().getAsInt());
        System.out.println("intStream的元素平均值是: " + intStream.average());
        System.out.println("intStream的元素總和是: " + intStream.sum());
        System.out.println("intStream的元素個數是: " + intStream.count());
        System.out.println("intStream是否包含任何元素平方大于10: "
                + intStream.anyMatch(ele -> ele * ele > 10));
        System.out.println("intStream的所有元素立方是否大于10: "
                + intStream.allMatch(ele -> ele * ele * ele > 10));

        // 每個元素都加1后映射成新的Stream
        IntStream intStreamNew = intStream.map(ele -> ele + 1);
        intStreamNew.forEach(ele -> System.out.println(ele));
        }
}

運行結果:將上述聚集方法所有執行結果放在一個里面進行展示,其實只能執行一條;

intStream的元素最大值是: 10
intStream的元素最小值是: -2
intStream的元素平均值是: OptionalDouble[3.0]
intStream的元素總和是: 12
intStream的元素個數是: 4
intStream是否包含任何元素平方大于10: true
intStream的所有元素立方是否大于10: false
2
-1
4
11

在上述示例中存在兩種聚集方法:“中間方法”和“末端方法”。

  • 中間方法:中間操作允許流保持打開狀態,并允許直接調用后續方法,如map()方法,返回值為另一個流;
  • 末端方法:末端方法是對流進行的最終操作,如sum()方法執行后,流就不可用,如果再用會報錯Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed

Stream的常用方法

中間方法

  • filter(Predicate predicate):過濾Stream中不符合predicate過濾條件的元素。
  • mapToXxx(ToXxxFunction mapper):使用ToXxxFunction對流中的元素執行一對一的轉換,方法返回的是新流中包含了ToXxxFunction轉換生成的所有元素。
  • peek(Consumer action):依次操作每個元素,返回的流與原有流包含相同的元素,用于調試。
  • distinct():用于排序流中所有重復的元素,有狀態的方法;
  • sorted():用于保證流中的元素在后續的訪問中處于有序狀態,也是有狀態的方法。
  • limit(long maxSize):用于保證對該流的后續訪問中最大允許訪問的元素個數,是一個有狀態的、短路方法。

末端方法

  • forEach(Consumer action):遍歷流中所有元素,執行action。
  • toArray():將流中所有元素轉換成一個數組。
  • reduce():用于某個操作合并流中元素。
  • min():返回流中元素的最小值。
  • max():返回流中元素的最大值。
  • sum():返回流中元素的總和。
  • count():返回流中所有元素的數量。
  • anyMatch(Predicate predicate):判斷流中是否至少包含一個元素符合predicate過濾條件。
  • allMatch(Predicate predicate):判斷流中是否所有元素符合predicate過濾條件。
  • noneMatch(Predicate predicate):判斷流中是否所有元素都不符合predicate過濾條件。
  • findFirst():返回流中的第一個元素。
  • findAny():返回流中的任意一個元素。

Collection中的stream()方法

public class DemoApplication {

    public static void main(String[] args) {
        // 創建集合
        Collection collection = new HashSet();

        // 添加元素
        collection.add("book_java編程思想");
        collection.add("book_c++核心技術");
        collection.add("book_java核心技術");
        collection.add("book_計算機網絡");
        collection.add("book01");
        collection.add("book02");
        collection.forEach(ele -> System.out.println(ele));

        System.out.println("-------------------------------------");

        System.out.println("包含java關鍵字的個數:"
                + collection.stream().filter(ele -> ((String)ele).contains("java")).count());
        System.out.println("長度小于7的個數:"
                + collection.stream().filter(ele -> ((String)ele).length() < 7).count());
        System.out.println("以book_為前綴的個數:"
                + collection.stream().filter(ele -> ((String)ele).startsWith("book_")).count());

        System.out.println("-------------------------------------");

        //先調用Collection的stream()方法將集合轉化為Stream;
        //再調用Stream的mapToInt()方法獲取Stream對象的IntStream對象;
        //最后調用forEach()方法遍歷IntStream中的元素。
        Collection collectionLength = new ArrayList();
        collection.stream().mapToInt(ele -> ((String)ele).length())
                .forEach(ele -> ((ArrayList) collectionLength).add(ele));
        //等價于collectionLength.forEach(ele -> System.out.println(ele));
        collectionLength.forEach(System.out::println);
        }
}

運行結果

book02
book01
book_java編程思想
book_java核心技術
book_計算機網絡
book_c++核心技術
-------------------------------------
包含java關鍵字的個數:2
長度小于7的個數:2
以book_為前綴的個數:4
-------------------------------------
6
6
13
13
10
12

??通過collection.stream().filter(Predicate<? super T> predicate).count()這種方式就可以替換文章中前面創建的PredicateUtil的方法。
??除了直接使用Stream流式接口去處理Collection集合的元素,我們還可以通過Collection接口的stream()方法返回集合對應的流。
步驟如下:

  1. 先調用Collection的stream()方法將集合轉化為Stream;
  2. 再調用Stream的mapToInt()方法獲取Stream對象的IntStream對象;
  3. 最后調用forEach()方法遍歷IntStream中的元素。

參考書籍《瘋狂Java》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容