我正在学习新的Java 8功能,在尝试使用流(java.util.stream.Stream
)和收集器时,我意识到流不能使用两次。
有没有办法重复使用它?
答案 0 :(得分:59)
如果您想要重用流,可以将流表达式包装在供应商中,并在需要新的时调用myStreamSupplier.get()
。例如:
Supplier<Stream<String>> sup = () -> someList.stream();
List<String> nonEmptyStrings = sup.get().filter(s -> !s.isEmpty()).collect(Collectors.toList());
Set<String> uniqueStrings = sup.get().collect(Collectors.toSet());
答案 1 :(得分:54)
应该只对一个流进行操作(调用中间或终端流操作)。
如果流实现检测到正在重用该流,则可能会抛出IllegalStateException。
所以答案是否定的,流不是要重复使用。
答案 2 :(得分:22)
正如其他人所说,&#34;不,你不能&#34;。
但是,对于许多基本操作来说,记住方便的summaryStatistics()
非常有用:
所以而不是:
List<Person> personList = getPersons();
personList.stream().mapToInt(p -> p.getAge()).average().getAsDouble();
personList.stream().mapToInt(p -> p.getAge()).min().getAsInt();
personList.stream().mapToInt(p -> p.getAge()).max().getAsInt();
你可以:
// Can also be DoubleSummaryStatistics from mapToDouble()
IntSummaryStatistics stats = personList.stream()
.mapToInt(p-> p.getAge())
.summaryStatistics();
stats.getAverage();
stats.getMin();
stats.getMax();
答案 3 :(得分:6)
Stream的整个想法是它一次性关闭。这允许您创建不可重新输入的源(例如,从网络连接读取行)而无需中间存储。但是,如果您想重用Stream内容,可以将其转储到中间集合中以获取“硬拷贝”:
import dataset
import configs
db_host = configs.hosts['server']
db_url = 'mysql://%s:%s@%s/%s?charset=utf8' % (db_host['user'], db_host['password'], db_host['ip'], db_host['database'])
db = dataset.connect(db_url)
如果您不想实现流,在某些情况下,有一些方法可以同时使用相同的流执行多项操作。例如,您可以参考this或this问题了解详情。
答案 4 :(得分:1)
来想一想,这将重新使用&#34;流是通过良好的内联操作实现所需结果的意愿。所以,基本上,我们在这里谈论的是,在我们编写终端操作后,我们可以做些什么来继续处理?
1)如果您的终端操作返回集合,则问题立即得到解决,因为每个集合都可以转回流(JDK 8)。
List<Integer> l=Arrays.asList(5,10,14);
l.stream()
.filter(nth-> nth>5)
.collect(Collectors.toList())
.stream()
.filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth));
2)如果终端操作返回可选,对Optional类进行JDK 9增强,则可以将Optional结果转换为流,并获得所需的内联操作:
List<Integer> l=Arrays.asList(5,10,14);
l.stream()
.filter(nth-> nth>5)
.findAny()
.stream()
.filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth));
3)如果你的终端操作返回别的东西,我真的怀疑你应该考虑一个流来处理这样的结果:
List<Integer> l=Arrays.asList(5,10,14);
boolean allEven=l.stream()
.filter(nth-> nth>5)
.allMatch(nth-> nth%2==0);
if(allEven){
...
}
答案 5 :(得分:1)
正如其他人所说,流对象本身无法重复使用。
但是,获得重用流效果的一种方法是将流创建代码提取到函数。
您可以通过创建包含流创建代码的方法或函数对象来完成此操作。然后你可以多次使用它。
示例:
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
// The normal way to use a stream:
List<String> result1 = list.stream()
.filter(i -> i % 2 == 1)
.map(i -> i * i)
.limit(10)
.map(i -> "i :" + i)
.collect(toList());
// The stream operation can be extracted to a local function to
// be reused on multiple sources:
Function<List<Integer>, List<String>> listOperation = l -> l.stream()
.filter(i -> i % 2 == 1)
.map(i -> i * i)
.limit(10)
.map(i -> "i :" + i)
.collect(toList());
List<String> result2 = listOperation.apply(list);
List<String> result3 = listOperation.apply(Arrays.asList(1, 2, 3));
// Or the stream operation can be extracted to a static method,
// if it doesn't refer to any local variables:
List<String> result4 = streamMethod(list);
// The stream operation can also have Stream as argument and return value,
// so that it can be used as a component of a longer stream pipeline:
Function<Stream<Integer>, Stream<String>> streamOperation = s -> s
.filter(i -> i % 2 == 1)
.map(i -> i * i)
.limit(10)
.map(i -> "i :" + i);
List<String> result5 = streamOperation.apply(list.stream().map(i -> i * 2))
.filter(s -> s.length() < 7)
.sorted()
.collect(toCollection(LinkedList::new));
}
public static List<String> streamMethod(List<Integer> l) {
return l.stream()
.filter(i -> i % 2 == 1)
.map(i -> i * i)
.limit(10)
.map(i -> "i :" + i)
.collect(toList());
}
另一方面,如果您已经有一个想要多次迭代的流对象,那么您必须将流的内容保存在某个集合对象中。
然后,您可以获得具有与集合相同内容的多个流。
示例:
public void test(Stream<Integer> stream) {
// Create a copy of the stream elements
List<Integer> streamCopy = stream.collect(toList());
// Use the copy to get multiple streams
List<Integer> result1 = streamCopy.stream() ...
List<Integer> result2 = streamCopy.stream() ...
}
答案 6 :(得分:0)
Functional Java library提供了自己的流,这些流可以满足您的要求,即被记住并且很懒。您可以使用其转换方法在Java SDK对象和FJ对象之间进行转换,例如给定JDK 8流,Java8.JavaStream_Stream(stream)
将返回可重用的FJ流。