#java #java_stream
Сегодня сидел разбирался с нововведениями Java 8. Когда попробовал на практике, сразу столкнулся с ошибкой. Наверное, я чего-то не знаю. Объясните, пожалуйста, что не так. Вот такой код: private boolean test( String line ) { String[] words = line.split(" "); StreamwordsStream = Arrays.asList(words).stream(); for( int i=0; i < controlWords.length; i++ ) { if( !wordsStream.anyMatch( Predicate.isEqual(controlWords[i]) ) ) { return false; } } return true; } Если массив controlWords имеет размер > 1, то всё время получаю ошибку java.lang.IllegalStateException: stream has already been operated upon or closed Если же метод чуть-чуть видоизменить, то проблема исчезнет: private boolean test( String line ) { String[] words = line.split(" "); //Stream wordsStream = Arrays.asList(words).stream(); for( int i=0; i < controlWords.length; i++ ) { if( !Arrays.asList(words).stream().anyMatch( Predicate.isEqual(controlWords[i]) ) ) { return false; } } return true; }
Ответы
Ответ 1
Как верно отметил @kofemann, Stream — одноразовая штука. В этом плане он похож на Iterator. Чтобы использовать его несколько раз, нужно создавать новый Stream. Если вы по какой-то причине хотите создание Stream вынести наружу (например, чтобы вам Stream передавали параметром), но при этом вам он нужен несколько раз, рекомендуется использовать Supplier: private boolean test(String line) { String[] words = line.split(" "); Supplier > wordsStream = () -> Arrays.asList(words).stream(); for (int i = 0; i < controlWords.length; i++) { if (!wordsStream.get().anyMatch(Predicate.isEqual(controlWords[i]))) { return false; } } return true; } Ещё обратите внимание, что есть метод Arrays.stream(), поэтому вам необязательно заворачивать сперва слова в список: Supplier > wordsStream = () -> Arrays.stream(words); Наконец, заметьте, что ваша задача решается гораздо легче старыми способами без Stream API: private boolean test(String line) { List words = Arrays.asList(line.split(" ")); for (int i = 0; i < controlWords.length; i++) { if (!words.contains(controlWords[i])) { return false; } } return true; } Однако можно повернуть в другую сторону и уже сам цикл for свернуть в Stream из controlWords: private boolean test(String line) { List words = Arrays.asList(line.split(" ")); return Arrays.stream(controlWords).allMatch(controlWord -> words.contains(controlWord)); } Тут можно заменить лямбду на ссылку: private boolean test(String line) { List words = Arrays.asList(line.split(" ")); return Arrays.stream(controlWords).allMatch(words::contains); } И даже заинлайнить words (после инлайнинга он всё равно один раз вычисляется!) private boolean test(String line) { return Arrays.stream(controlWords).allMatch(Arrays.asList(line.split(" "))::contains); } Ответ 2
Stream нельзя использовать несколько раз. Поток пропускается один раз. По этому, если цикл повторяется больше одного раза то код работает не корректно. Во втором примере, каждый раз создаётся новый stream .
Комментариев нет:
Отправить комментарий