天天看點

Java 使用 Stream API 篩選 ListJava 使用 Stream API 篩選 List

Java 使用 Stream API 篩選 List

前言

上課的時候看到老師用疊代器來周遊 List 中的元素的時候,我的内心是極其嫌棄的,這種疊代方法不能直接通路目前的元素,而且寫起來也麻煩。于是上網查了查 Java 有沒有類似于 Linq 的東西,雖然發現了一個 JLinq 但是抱着學習的心态,還是沒有用這個東西。看了看 Intellji 的自動補全然後想出了下面的代碼。

題目

删除 List 中資訊重複的學生

解法一

LinkedList<T3.Student> repo3 = new T3.StudentTest().getRepo();
repo3.removeIf(s->repo3.indexOf(s)!=repo3.lastIndexOf(s));           

這個方法看起來是沒有很大的問題的,但是如果問題稍微變了一下,這就沒用了。

題目 update

删除 List 中資訊部分重複的學生,也就是隻要姓名、年齡相同的學生就認定為資訊重複,即使學号不同。

解法二

上面的解法一到了這個問題就失效了,對于這個問題我隻能想到用下面的代碼來解決

for (int i = 0; i < repo3.size(); i++)
        {
            T3.Student stu = repo3.get(i);//Lambda 表達式不允許我用沒被引用的變量,是以就把這句單獨提了出來
            repo3.removeIf(s->s.equals(stu));//根據題意定義的 equals 方法
        }           

增加了一個 

for

 循環,其餘的基本沒變,但是代碼的簡潔程度相較于使用疊代器得到了大幅度提高。

踩到的坑

0.為毛不用

foreach

或者

forEach

循環?

foreach

不能适應動态變化的集合,因為我在動作中删除了元素。

forEach

雖然是一個内部循環,有并行計算的優勢,但是還是由于上面的原因不能使用。

1.Stream 接口的操作不會對原有的資料産生影響。

repo3.removeAll(repo3.stream()
     .filter(
             s -> repo3.stream().filter(stu -> stu.equals(s)).count() != 0)
     .collect(Collectors.toList()));           

本來我是想用這種方法拿到所有重複的元素,然而事實上是不行的,因為Stream 接口的操作不會對原有的資料産生影響。導緻第二個 

filter

 會把所有元素重新掃描一遍,是以需要改成下面的代碼:

repo3.removeIf
        (
                s -> repo3
                .subList(repo3.indexOf(s),repo3.size())
                .stream()
                .filter(stu -> stu.equals(s))
                .count() != 0
        );           

看起來好像比解法二複雜了許多但是在效率上有很大的進步,

Stream API

是并行化的,比外部循環不知道要高到哪裡去了,然而這裡還存在一個問題,就是在

subList

中獲得對目前元素的索引的速度可能會拖慢效率,然而,在這道題目的測試用例當中學号起到了索引的作用,然後這裡的效率可以大幅度提升。

總結

一開始準備用 

Stream API

 我是拒絕的,我看到它是以方法的形式出現的,我還以為會出現類型轉換,後來發現這是 Java 缺少 

extend methods

 才出現的東西。然後這個東西實作了跟 Linq 差不多的功能,配合 Lambda 表達式很好用。

那麼下面給出最終的版本:

repo3.removeIf
                (
                        s -> repo3
                        .stream()
                        .filter(stu -> stu.equals(s))
                        .count() != 0
                );           

這裡之是以不需要把 list 截斷可能是因為 

removeif

也是一個

stream

方法。