有条件地向Java8流添加操作

有条件地向Java8流添加操作,java,java-8,limit,java-stream,Java,Java 8,Limit,Java Stream,我想知道是否可以根据流之外设置的某种条件向流添加操作。例如,如果我的limit变量不等于-1,我想向流中添加一个限制操作 我的代码目前看起来是这样的,但我还没有看到以这种方式使用流的其他示例,其中流对象被重新分配给应用于自身的中间操作的结果: // Do some stream stuff stream = stream.filter(e -> e.getTimestamp() < max); // Limit the stream if (limit != -1) { st

我想知道是否可以根据流之外设置的某种条件向流添加操作。例如,如果我的
limit
变量不等于
-1
,我想向流中添加一个限制操作

我的代码目前看起来是这样的,但我还没有看到以这种方式使用流的其他示例,其中流对象被重新分配给应用于自身的中间操作的结果:

// Do some stream stuff
stream = stream.filter(e -> e.getTimestamp() < max);

// Limit the stream
if (limit != -1) {
   stream = stream.limit(limit);
}

// Collect stream to list
stream.collect(Collectors.toList());
//做一些流的事情
stream=stream.filter(e->e.getTimestamp()

如本文所述,在调用终端操作之前,不会实际应用过滤器。因为我在调用终端操作之前重新分配了stream的值,所以上面的代码仍然是使用Java 8 streams的正确方法吗?

我认为您的第一行需要是:

stream = stream.filter(e -> e.getTimestamp() < max);
stream=stream.filter(e->e.getTimestamp()

因此,您可以在后续操作中使用筛选器返回的流,而不是原始流。

有两种方法可以做到这一点

// Do some stream stuff
List<E> results = list.stream()
                  .filter(e -> e.getTimestamp() < max);
                  .limit(limit > 0 ? limit : list.size())
                  .collect(Collectors.toList());
//做一些流的事情
列表结果=List.stream()
.filter(e->e.getTimestamp()0?limit:list.size())
.collect(Collectors.toList());

//做一些流的事情
stream=stream.filter(e->e.getTimestamp()
由于这是函数式编程,您应该始终处理每个函数的结果。您应该特别避免修改这种编程风格中的任何内容,并尽可能将所有内容视为不可变的

因为我在调用终端操作之前重新分配了stream的值,所以上面的代码仍然是使用Java8流的正确方法吗


它应该可以工作,但是它是命令式和功能性编码的混合体。我建议按照我的第一个答案将其作为固定流来编写。

链式调用系列和存储中间返回值的调用系列之间没有语义上的区别。因此,以下代码片段是等效的:

a = object.foo();
b = a.bar();
c = b.baz();
.limit(condition? aLimit: Long.MAX_VALUE)

在任何一种情况下,都会根据前一次调用的结果调用每个方法。但在后一种情况下,中间结果不会存储,而是在下一次调用时丢失。在流API的情况下,在调用流上的下一个方法后,不能使用中间结果,因此链接是使用流的自然方式,因为它本质上确保不会对返回的引用调用多个方法

尽管如此,只要遵守不多次使用返回的引用的约定,就可以存储对流的引用。通过像您的问题一样使用它,即用下一次调用的结果覆盖变量,您还可以确保不会对返回的引用调用多个方法,因此,这是一种正确的用法。当然,这只适用于相同类型的中间结果,因此当您使用
map
flatMap
获取不同引用类型的流时,您不能覆盖局部变量。然后,您必须小心不要再次使用旧的局部变量,但是,正如前面所说的,只要在下一次调用之后不使用它,中间存储就没有问题

有时,您必须存储它,例如

try(Stream<String> stream = Files.lines(Paths.get("myFile.txt"))) {
    stream.filter(s -> !s.isEmpty()).forEach(System.out::println);
}
假设您所能遇到的最大元素数为
Long.MAX\u VALUE
,但流中的元素可能多于此数,甚至可能是无限的

.limit(condition? aLimit: list.size())
当流源为<代码>列表
时,正在中断流的惰性计算。原则上,可变流源可以合法地得到任意更改,直到终端操作开始。结果将反映到目前为止所做的所有修改。当添加包含
list.size()
的中间操作时,即此时列表的实际大小,应用于此点和终端操作之间集合的后续修改可能会使此值的含义不同于预期的“实际无限制”语义

与之相比:

对于性能良好的流源,可以在终端操作开始之前修改源,这些修改将反映在覆盖的元素中。例如,考虑下面的代码:

List<String> l = new ArrayList(Arrays.asList("one", "two"));
Stream<String> sl = l.stream();
l.add("three");
String s = sl.collect(joining(" "));
listl=newarraylist(Arrays.asList(“一”、“二”));
Stream sl=l.Stream();
l、 添加(“三”);
字符串s=sl.collect(连接(“”);
首先创建一个由两个字符串组成的列表:“一”;和“两个”。然后根据该列表创建一个流。接下来,通过添加第三个字符串修改列表:“三”。最后,流的元素被收集并连接在一起。由于列表是在终端收集操作开始之前修改的,因此结果将是“一二三”字符串

当然,这是一种罕见的情况,通常情况下,程序员将制定一个完整的流管道,而无需修改中间的源集合。尽管如此,不同的语义仍然存在,一旦进入这样一个角落,它可能会变成一个很难找到的bug

此外,由于它们不是等价的,流API永远不会将这些值识别为“实际上没有限制”。即使指定
Long.MAX_VALUE
也意味着流实现必须跟踪已处理元素的数量,以确保遵守限制。因此,不添加
限制
操作比添加
try(Stream<String> srcStream = Files.lines(Paths.get("myFile.txt"))) {
    Stream<String> tmp = srcStream.filter(s -> !s.isEmpty());
    // must not be use variable srcStream here:
    tmp.forEach(System.out::println);
}
.limit(condition? aLimit: Long.MAX_VALUE)
.limit(condition? aLimit: list.size())
List<String> l = new ArrayList(Arrays.asList("one", "two"));
Stream<String> sl = l.stream();
l.add("three");
String s = sl.collect(joining(" "));