Collection之removeif()方法使用

Collection之removeif()方法使用

錯誤示範:

在集合框架的使用中,經常會有遍歷中需要添加元素或者刪除元素的情況出現,如果使用此方法

ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }
        for (Integer i : list) {
            //當i是偶數就刪除此元素
            if (i % 2 == 0) {
                list.remove(i);
            }
        }

運行時會出現

Exception in thread "main" java.util.ConcurrentModificationException

api中是這樣解釋的

當不允許這樣的修改時,可以通過檢測到對象的併發修改的方法來拋出此異常。

例如,一個線程通常不允許修改集合,而另一個線程正在遍歷它。 一般來說,在這種情況下,迭代的結果是未定義的。 某些迭代器實現(包括由JRE提供的所有通用集合實現的實現)可能會選擇在檢測到此行爲時拋出此異常。 這樣做的迭代器被稱爲故障快速迭代器,因爲它們快速而乾淨地失敗,而是在未來未確定的時間冒着任意的非確定性行爲。

請注意,此異常並不總是表示對象已被不同的線程同時修改。 如果單個線程發出違反對象合同的方法調用序列,則該對象可能會拋出此異常。 例如,如果線程在使用故障快速迭代器迭代集合時直接修改集合,則迭代器將拋出此異常。

請注意,故障快速行爲無法保證,因爲一般來說,在不同步併發修改的情況下,無法做出任何硬性保證。 失敗快速的操作儘可能地拋出ConcurrentModificationException 。 因此,編寫依賴於此異常的程序的正確性將是錯誤的: ConcurrentModificationException應僅用於檢測錯誤。

簡單的說就是在遍歷的過程中對集合進行修改就會拋出此異常.

正確方法:

改進的方法有兩種:

使用迭代器:

		ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer i = iterator.next();
            if (i % 2 == 0) {
                list.remove(i);
            }
        }

遍歷完後再刪除:

ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }
        ArrayList<Integer> list02 = new ArrayList<>();
        for (Integer i : list) {
            if (i % 2 == 0) {
                list02.add(i);
            }
        }
        list.removeAll(list02);
        System.out.println(list);

都是比較麻煩的.

使用removeIf(Predicate<? super E> filter) 方法改進:

在JDK1.8中,Collection中加入了removeIf方法,其子類自然也繼承了此方法

default boolean removeIf(Predicate<? super E> filter) 刪除滿足給定謂詞的此集合的所有元素。

		ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }
		//只需一行代碼
		//使用此方法刪除list集合中滿足過濾條件的元素
        list.removeIf(integer -> integer % 2 == 0);
        System.out.println(list);

可以看到,使用removeIf()方法後,原來需要最多7行的代碼變成了一行!

以下爲部分源碼

default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }

可以看到底層源碼也是使用迭代器的,和上一步的方法原理相同,所以推薦使用此更方便,精簡的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章