繁体   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