2015-11-09 3 views
1

У меня есть пара predicates, что я все хочу быть удовлетворенным.anyMatch внутри allMatch

То, что может удовлетворить эти предикаты, - это несколько строк. Отдельная строка не должна удовлетворять всем (или любым) из этих предикатов, но после того, как я посмотрел на последнюю строку, все предикаты должны быть удовлетворены.

Мой первый дубль, чтобы представить эту проблему в Java, чтобы использовать Stream «s 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

Более или менее, сделать 'thingsToTest' коллекцию, которая может быть restreamed, а не' Stream' сам, что может только использовать один раз. –

ответ

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

Когда вам нужно использовать несколько раз Потока, общее решение заключается в создании 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; 
Смежные вопросы