我有几个predicates,我都希望得到满足。
能够满足这些谓词的东西是少数几个字符串。单个字符串不必满足所有(或任何)谓词,但在我查看最后一个字符串后,所有谓词都必须满足。
我首先在Java中表示这个问题是使用Stream' allMatch
和anyMatch
,因为我想要所有谓词匹配要测试的任何:
Stream<String> thingsToTest = Stream.of("Hi", "predicates!", "oddball");
Predicate<String> startsWithH = string -> string.startsWith("H");
Predicate<String> endsWithBang = string -> string.endsWith("!");
Stream<Predicate<String>> predicates = Stream.of(startsWithH, endsWithBang);
// All of the strings have the chance to satisfy any predicate
boolean predicatesSatisfied = predicates.allMatch(pred -> thingsToTest.anyMatch(pred::test));
// I expect this to print "true"
System.out.println(predicatesSatisfied);
可悲的是,这不起作用,但终止于IllegalStateException
,告诉我stream has already been operated upon or closed
,这不应该是一个很大的惊喜,因为我给每个谓词使用字符串流一遍又一遍地为一个新的机会来满足谓词。
And streams are not meant to be reused for good reasons.
那么我该如何避免这种异常呢?是否有anyMatch
或allMatch
更优雅的替代方案?
答案 0 :(得分:3)
要绕过IllegalStateException
我使用List
字符串并调用其stream()
方法:
// Use List instead of Stream
List<String> thingsToTest = Arrays.asList("Hi", "predicates!", "oddball");
// Same old
Predicate<String> startsWithH = string -> string.startsWith("H");
Predicate<String> endsWithBang = string -> string.endsWith("!");
Stream<Predicate<String>> predicates = Stream.of(startsWithH, endsWithBang);
// Call stream() on the List
boolean predicatesSatisfied = predicates.allMatch(pred -> thingsToTest.stream().
anyMatch(pred::test));
虽然这样做很好,但我不确定这是否是最优雅的方式,所以如果您有更好的想法,请继续发布您的代码或建议。
答案 1 :(得分:1)
当您需要多次使用Stream时,常见的解决方案是创建Supplier<Stream>
而不是:
Supplier<Stream<String>> thingsToTest = () -> Stream.of("Hi", "predicates!", "oddball");
....
boolean predicatesSatisfied = predicates.allMatch(
pred -> thingsToTest.get().anyMatch(pred::test));
与@MatthiasBraun建议不同,使用Supplier
并不总是需要在逐字汇集中实际存储所有流元素。例如,这样的事情是可能的:
Supplier<Stream<String>> thingsToTest =
() -> IntStream.range(0, 10000).mapToObj(String::valueOf);
您只需关心供应商始终返回相同的流元素。
如果您已有集合,那么您也可以创建供应商:
List<String> list = Arrays.asList("Hi", "predicates!", "oddball");
Supplier<Stream<String>> thingsToTest = list::stream;