代码之家  ›  专栏  ›  技术社区  ›  user1589188

懒惰地调用java流中的方法

  •  0
  • user1589188  · 技术社区  · 3 年前

    我有一个昂贵的方法,我只想在流中必要时调用它。以下是一个示例:

    public static Optional<MyObject> findTarget(String input, List<MyObject> myList) {
        return Stream.concat(myList.stream(), expensive().stream()).filter(o -> o.hasName(input)).findFirst();
    }
    

    目标是找到目标 MyObject 从…起 myList 基于 input 值,但如果不在 myList 只有这样它才会呼叫 expensive() 返回一个更大的列表并从中查看。

    上面的例子似乎并没有做到这一点 Stream.concat 将呼叫 昂贵的 在消费所有之前已经 myList .

    我能想到的一个丑陋的解决方案是分两步进行,例如:

    return myList.stream().filter(o -> o.hasName(input)).findFirst().or(
        () -> expensive().stream().filter(o -> o.hasName(input)).findFirst());
    

    但之后我将不得不重复过滤器和其余部分两次。

    有没有更好的解决方案,甚至是Stream的一个内衬可以做到这一点?

    1 回复  |  直到 3 年前
        1
  •  7
  •   モキャデ    3 年前

    您可以通过串联进行惰性评估 Supplier<List<MyObject>> 而不是 List<MyObject> .

    public static Optional<MyObject> findTarget(String input, List<MyObject> myList) {
        List<Supplier<List<MyObject>>> concat = List.of(() -> myList, () -> expensive());
        return concat.stream()
            .flatMap(supplier -> supplier.get().stream())
            .filter(o -> o.hasName(input))
            .findFirst();
    }
    

    测验

    record MyObject(String s) {
        public boolean hasName(String in) {
            return s.equals(in);
        }
    }
    
    static List<MyObject> expensive() {
        System.out.println("expensive() called");
        return List.of(new MyObject("z"));
    }
    
    public static void main(String[] args) {
        List<MyObject> myList = List.of(new MyObject("a"));
        System.out.println("case 1: " + findTarget("a", myList));
        System.out.println("case 2: " + findTarget("x", myList));
    }
    

    输出

    case 1: Optional[MyObject[s=a]]
    expensive() called
    case 2: Optional.empty
    

    或者,您可以这样做:

    public static Optional<MyObject> findTarget(String input, List<MyObject> myList) {
        return Stream.of(
                (Supplier<List<MyObject>>) () -> myList,
                (Supplier<List<MyObject>>) () -> expensive())
            .flatMap(supplier -> supplier.get().stream())
            .filter(o -> o.hasName(input))
            .findFirst();
    }
    
        2
  •  2
  •   Didier L    3 年前

    另一种可能更容易理解的替代方案是用单独的方法提取流逻辑:

    private static Optional<MyObject> findInternal(String input, List<MyObject> myList) {
        return myList.stream().filter(o -> o.hasName(input)).findFirst();
    }
    

    然后简单地调用两次:

    public static Optional<MyObject> findTarget(String input, List<MyObject> myList) {
        return findInternal(input, myList).or(() -> findInternal(input, expensive()));
    }
    
    推荐文章