简体   繁体   English

在流中使用Java 8 Supplier实现延迟评估

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

I am trying to achieve lazy evaluation using Supplier in a stream like this 我正在尝试在像这样的流中使用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());
    }

But this will call getExpensiveList() method for every element in the list. 但这将为列表中的每个元素调用getExpensiveList()方法。 I am trying not to be verbose and don't want to write something like this ie to add not empty checks and stuff. 我正在尝试不要太冗长,也不想写这样的东西,即不添加空支票和东西。

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());
    }

I don't think this is possible using only standard Java classes. 我认为仅使用标准Java类是不可能的。 But you could write your own lazy evaluator and use that, for example (untested): 但是您可以编写自己的惰性评估器并使用它,例如(未试用):

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;
    }
}

There are other possibilities as well, see for example this question . 也有其他可能性,例如参见此问题

But beware! 但是要当心! If you add lazy evaluation, you have a mutable data structure, so if you use it in a multithreaded environment (or a parallel stream), add synchronization. 如果添加惰性评估,则您的数据结构是可变的,因此,如果在多线程环境(或并行流)中使用它,请添加同步。

But, I would use your verbose version. 但是,我将使用您的详细版本。 It's immediately clear what it does, and it is only four lines longer. 现在可以清楚地知道它的作用,而且只长了四行。 (In real code I expect that those four lines are irrelevant.) (在实际代码中,我希望这四行无关紧要。)

You second variant can be simplified to 您的第二个变体可以简化为

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

It makes the use of a Supplier pointless, as even the call to getExpensiveList() will be done only when the list is non-empty. 它使Supplier的使用毫无意义,因为只有当列表为非空时, getExpensiveList()进行调用。 But on the other hand, that's the maximum laziness you can get anyway, ie not to request the expensive list when the other list is empty. 但是,另一方面,这就是您可以获得的最大懒惰,即在另一个列表为空时不请求昂贵的列表。 In either case, the expensive list will be requested for the first element already when the list is not empty. 无论哪种情况,当列表不为空时,都会为第一个元素请求昂贵的列表。

If the expensive list can become large, you should use 如果昂贵的清单可能很大,则应使用

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

instead, to avoid repeated linear searches. 而是避免重复线性搜索。 Or redesign getExpensiveList() to return a Set in the first place. 或重新设计getExpensiveList()以首先返回Set

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM