簡體   English   中英

在流中使用Java 8 Supplier實現延遲評估

[英]Using Java 8 Supplier in streams to achieve lazy evaluation

我正在嘗試在像這樣的流中使用Supplier進行惰性評估

public static void main(String[] args) {

        Supplier<List<String>> expensiveListSupplier= getExpensiveList();
        getList().stream()
                .filter(s -> expensiveListSupplier.get().contains(s))
                .forEach(System.out::println);
    }

    private static Supplier<List<String>> getExpensiveList() {
        return () -> Stream
                .of("1", "2", "3")
                .peek(System.out::println)
                .collect(Collectors.toList());
    }

    private static List<String> getList() {
        return Stream.of("2", "3")
                .collect(Collectors.toList());
    }

但這將為列表中的每個元素調用getExpensiveList()方法。 我正在嘗試不要太冗長,也不想寫這樣的東西,即不添加空支票和東西。

public static void main(String[] args) {

        Supplier<List<String>> expensiveListSupplier = getExpensiveList();
        List<String> list = getList();
        if (!list.isEmpty()) {
            List<String> expensiveList = expensiveListSupplier.get();
            list.stream()
                    .filter(expensiveList::contains)
                    .forEach(System.out::println);
        }    
    }

    private static Supplier<List<String>> getExpensiveList() {
        return () -> Stream
                .of("1", "2", "3")
                .peek(System.out::println)
                .collect(Collectors.toList());
    }

    private static List<String> getList() {
        return Stream.of("2", "3")
                .collect(Collectors.toList());
    }

我認為僅使用標准Java類是不可能的。 但是您可以編寫自己的惰性評估器並使用它,例如(未試用):

public class LazyValue<T> implements Supplier<T> {
    private T value;
    private final Supplier<T> initializer;
    public LazyValue(Supplier<T> initializer) {
        this.initializer = initializer;
    } 
    public T get() {
        if (value == null) {
            value = initializer.get();
        }
        return value;
    }
}

也有其他可能性,例如參見此問題

但是要當心! 如果添加惰性評估,則您的數據結構是可變的,因此,如果在多線程環境(或並行流)中使用它,請添加同步。

但是,我將使用您的詳細版本。 現在可以清楚地知道它的作用,而且只長了四行。 (在實際代碼中,我希望這四行無關緊要。)

您的第二個變體可以簡化為

List<String> list = getList();
if(!list.isEmpty()) {
    list.stream()
        .filter(getExpensiveList().get()::contains)
        .forEach(System.out::println);
}

它使Supplier的使用毫無意義,因為只有當列表為非空時, getExpensiveList()進行調用。 但是,另一方面,這就是您可以獲得的最大懶惰,即在另一個列表為空時不請求昂貴的列表。 無論哪種情況,當列表不為空時,都會為第一個元素請求昂貴的列表。

如果昂貴的清單可能很大,則應使用

List<String> list = getList();
if(!list.isEmpty()) {
    list.stream()
        .filter(new HashSet<>(getExpensiveList().get())::contains)
        .forEach(System.out::println);
}

而是避免重復線性搜索。 或重新設計getExpensiveList()以首先返回Set

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM