相关疑难解决方法(0)

takeWhile()与flatmap的工作方式不同

我正在创建片段与takeWhile探索其可能性.与flatMap结合使用时,行为与预期不符.请在下面找到代码段.

String[][] strArray = {{"Sample1", "Sample2"}, {"Sample3", "Sample4", "Sample5"}};

Arrays.stream(strArray)
        .flatMap(indStream -> Arrays.stream(indStream))
        .takeWhile(ele -> !ele.equalsIgnoreCase("Sample4"))
        .forEach(ele -> System.out.println(ele));
Run Code Online (Sandbox Code Playgroud)

实际产量:

Sample1
Sample2
Sample3
Sample5
Run Code Online (Sandbox Code Playgroud)

ExpectedOutput:

Sample1
Sample2
Sample3
Run Code Online (Sandbox Code Playgroud)

期望的原因是takeWhile应该执行直到内部条件变为真.我还在flatmap中添加了printout语句以进行调试.流返回两次,符合预期.

但是,如果链中没有flatmap,这样可以正常工作.

String[] strArraySingle = {"Sample3", "Sample4", "Sample5"};
Arrays.stream(strArraySingle)
        .takeWhile(ele -> !ele.equalsIgnoreCase("Sample4"))
        .forEach(ele -> System.out.println(ele));
Run Code Online (Sandbox Code Playgroud)

实际产量:

Sample3
Run Code Online (Sandbox Code Playgroud)

这里实际输出与预期输出匹配.

免责声明:这些代码段仅用于代码练习,不提供任何有效的用例.

更新: 错误JDK-8193856:修复将作为JDK 10的一部分提供.更改将更正whileOps Sink :: accept

@Override 
public void accept(T t) {
    if (take = predicate.test(t)) {
        downstream.accept(t);
    }
}
Run Code Online (Sandbox Code Playgroud)

改变实施:

@Override
public void accept(T t) {
    if (take && …
Run Code Online (Sandbox Code Playgroud)

java lambda java-stream java-9

75
推荐指数
4
解决办法
3874
查看次数

递归使用Stream.flatMap()

考虑以下课程:

public class Order {

    private String id;

    private List<Order> orders = new ArrayList<>();

    @Override
    public String toString() {
        return this.id;
    }

    // getters & setters
}
Run Code Online (Sandbox Code Playgroud)

注意:重要的是要注意我无法修改此类,因为我正在从外部API中使用它.

还要考虑以下订单层次结构:

Order o1 = new Order();
o1.setId("1");
Order o11 = new Order();
o11.setId("1.1");
Order o111 = new Order();
o111.setId("1.1.1");
List<Order> o11Children = new ArrayList<>(Arrays.asList(o111));
o11.setOrders(o11Children);

Order o12 = new Order();
o12.setId("1.2");
List<Order> o1Children = new ArrayList<>(Arrays.asList(o11, o12));
o1.setOrders(o1Children);

Order o2 = new Order();
o2.setId("2");
Order o21 = new …
Run Code Online (Sandbox Code Playgroud)

java java-8 java-stream

30
推荐指数
2
解决办法
1万
查看次数

注册流"完成"钩子

使用Java 8 StreamAPI,我想注册一个"完成钩子",类似于:

Stream<String> stream = Stream.of("a", "b", "c");

// additional filters / mappings that I don't control
stream.onComplete((Completion c) -> {
    // This is what I'd like to do:
    closeResources();

    // This might also be useful:
    Optional<Throwable> exception = c.exception();
    exception.ifPresent(e -> throw new ExceptionWrapper(e));
});
Run Code Online (Sandbox Code Playgroud)

我为什么要那么做的原因是因为我想包装在一个资源Stream的API客户端,消费,我想的是Stream,一旦它被消耗自动清理资源.如果可能,那么客户可以致电:

Collected collectedInOneGo =
Utility.something()
       .niceLookingSQLDSL()
       .moreDSLFeatures()
       .stream()
       .filter(a -> true)
       .map(c -> c)
       .collect(collector);
Run Code Online (Sandbox Code Playgroud)

而不是目前所需要的:

try (Stream<X> meh = Utility.something()
                            .niceLookingSQLDSL()
                            .moreDSLFeatures()
                            .stream()) {

    Collected collectedWithUglySyntacticDissonance = …
Run Code Online (Sandbox Code Playgroud)

java java-8 java-stream

27
推荐指数
3
解决办法
1967
查看次数

在Java中,我如何有效和优雅地流式传输树节点的后代?

假设我们有一个由唯一Strings 标识的对象集合,以及一个Tree定义它们层次结构的类.该类使用Mapfrom节点(由其ID表示)到Collection其各自子节点的s来实现.

class Tree {
  private Map<String, Collection<String>> edges;

  // ...

  public Stream<String> descendants(String node) {
    // To be defined.
  }
}
Run Code Online (Sandbox Code Playgroud)

我想启用流式节点的后代.一个简单的解决方案是:

private Stream<String> children(String node) {
    return edges.getOrDefault(node, Collections.emptyList()).stream();
}

public Stream<String> descendants(String node) {
    return Stream.concat(
        Stream.of(node),
        children(node).flatMap(this::descendants)
    );
}
Run Code Online (Sandbox Code Playgroud)

在继续之前,我想对此解决方案做出以下断言.(我对这些是正确的吗?)

  1. Stream返回的descendants消耗资源(时间和内存) - 相对于树的大小 - 以与手动编码递归相同的复杂度顺序行走.特别地,表示迭代状态(Streams,Spliterators,...)的中间对象形成堆栈,因此在任何给定时间的存储器要求与树的深度具有相同的复杂度.

  2. 据我所知,只要我在执行终止操作Stream从返回descendants,根级别调用flatMap将导致所有包含Stream秒-一个用于每个(递归)呼叫descendants-被立即实现.因此,结果Stream …

java algorithm java-8 java-stream

18
推荐指数
2
解决办法
3060
查看次数

如何使用lambda流迭代嵌套列表?

我正在尝试使用`stream将以下代码重构为lambda表达式,尤其是嵌套的foreach循环:

public static Result match (Response rsp) {
    Exception lastex = null;

    for (FirstNode firstNode : rsp.getFirstNodes()) {
        for (SndNode sndNode : firstNode.getSndNodes()) {
            try {
                if (sndNode.isValid())
                return parse(sndNode); //return the first match, retry if fails with ParseException
            } catch (ParseException e) {
                lastex = e;
            }
        }
    }

    //throw the exception if all elements failed
    if (lastex != null) {
        throw lastex;
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)

我开始时:

rsp.getFirstNodes().forEach().?? // how to iterate the nested 2ndNodes?
Run Code Online (Sandbox Code Playgroud)

java lambda java-8 java-stream

17
推荐指数
2
解决办法
4万
查看次数

Stream上的收集操作是否会关闭流和底层资源?

以下代码是否需要包含在try-with-resources中以确保底层文件已关闭?

List<String> rows = Files.lines(inputFilePath).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

java file-io java-8 try-with-resources java-stream

16
推荐指数
2
解决办法
2741
查看次数

Java 8和11之间的流差异

考虑以下代码:

public static void main(String[] args) {
    Stream.iterate(1, i -> i + 1)
            .flatMap(i -> Stream.of(i, i, i))
            .peek(System.out::println)
            .limit(4)
            .forEach(i -> {});
}
Run Code Online (Sandbox Code Playgroud)

Java 8的输出:

1
1
1
2
2
2
Run Code Online (Sandbox Code Playgroud)

在Java 11中:

1
1
1
2
Run Code Online (Sandbox Code Playgroud)

这是Java 8中的错误或预期的行为,在11中进行了更改吗?

上面的代码只是演示不同行为的示例,但是更重要的含义是,以下代码在Java 11中显示1,2,3,但在Java 8中进入了无限循环:

    Stream.iterate(0, i -> i + 10)
            .flatMap(i -> Stream.iterate(i + 1, j -> j + 1))
            .limit(3)
            .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

java java-8 java-stream flatmap java-11

16
推荐指数
2
解决办法
701
查看次数

并行无限 Java 流耗尽内存

我试图理解为什么下面的 Java 程序给出了OutOfMemoryError,而没有的相应程序没有.parallel()

System.out.println(Stream
    .iterate(1, i -> i+1)
    .parallel()
    .flatMap(n -> Stream.iterate(n, i -> i+n))
    .mapToInt(Integer::intValue)
    .limit(100_000_000)
    .sum()
);
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

  1. 这个程序的预期输出是什么?

    没有.parallel()它似乎只是输出sum(1+2+3+...),这意味着它只是“卡在” flatMap 中的第一个流,这是有道理的。

    使用并行我不知道是否有预期的行为,但我的猜测是它以某种方式交错了第一个n左右的流,n并行工作人员的数量在哪里。根据分块/缓冲行为,它也可能略有不同。

  2. 是什么导致它耗尽内存?我特别想了解这些流是如何在幕后实现的。

    我猜有什么东西阻塞了流,所以它永远不会完成并且能够摆脱生成的值,但我不太清楚事物的评估顺序以及缓冲发生的位置。

编辑:如果相关,我使用的是 Java 11。

编辑 2:显然即使对于简单的程序也会发生同样的事情IntStream.iterate(1,i->i+1).limit(1000_000_000).parallel().sum(),所以它可能与limit而不是的懒惰有关flatMap

java out-of-memory lazy-evaluation java-stream

16
推荐指数
2
解决办法
1484
查看次数

Java流操作调用

任何人都可以指向官方Java文档,该文档描述了Stream将为每个元素调用每个"非干扰和无状态"中间操作的次数.

例如:

Arrays.asList("1", "2", "3", "4").stream()
        .filter(s -> check(s))
        .forEach(s -> System.out.println(s));

public boolean check(Object o) {
    return true;
} 
Run Code Online (Sandbox Code Playgroud)

以上目前将调用check方法4次.

是否有可能在JDK的当前版本或未来版本中,该check方法的执行次数多于或少于从List或任何其他标准Java API创建的流中的元素数量

java java-8 java-stream

14
推荐指数
1
解决办法
395
查看次数

flatMap是否保证是懒惰的?

请考虑以下代码:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();
Run Code Online (Sandbox Code Playgroud)

fetchDataFromInternet当第一个足够的时候会被叫第二个网址吗?

我尝试了一个较小的例子,看起来像预期的那样工作.即逐个处理数据但是可以依赖这种行为吗?如果没有,请.sequential().flatMap(...)帮助前打电话吗?

    Stream.of("one", "two", "three")
            .flatMap(num -> {
                System.out.println("Processing " + num);
                // return FetchFromInternetForNum(num).data().stream();
                return Stream.of(num);
            })
            .peek(num -> System.out.println("Peek before filter: "+ num))
            .filter(num -> num.length() > 0)
            .peek(num -> System.out.println("Peek after filter: "+ num))
            .forEach(num -> {
                System.out.println("Done " + num);
            });
Run Code Online (Sandbox Code Playgroud)

输出:

Processing one
Peek before filter: one
Peek after filter: one
Done one
Processing two
Peek before filter: two
Peek after filter: …
Run Code Online (Sandbox Code Playgroud)

java java-8 java-stream flatmap

11
推荐指数
2
解决办法
1304
查看次数