Вам нужно каждый раз пересчитывать java Stream <T>? - PullRequest
0 голосов
/ 27 мая 2018

Я написал этот метод:

public static void main(String... args) {
    try (var linesStream = Files.lines(Paths.get("C:\\Users\\paul\\Desktop\\java.txt"))) {
        Stream<String> words = linesStream.
                flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct();
        System.out.println("There are " + words.count() + " distinct words in this file, here they are:");
        words.forEach(System.out::println);
    } catch (IOException e) {
        System.err.println(e.getMessage());
    }
}

Проблемы, с которыми я здесь сталкиваюсь, состоят в том, что я оперирую словами Stream<String> дважды.Чтобы сделать это, вам нужно явно перестроить этот поток или есть какой-то магический метод сброса, который я мог бы использовать?

Кроме того, чтобы снова перестроить поток слов, я должен перестроить linesStreamи обернуть это в другой блок try / catch здесь ... Очень многословно.Какой способ облегчить написание таких вещей?

Наверное, я мог бы сделать:

    static Stream<String> getStreamFromFile() throws IOException {
        return Files.lines(Paths.get("C:\\Users\\paul\\Desktop\\java.txt"));
    }

    static Stream<String> getDistinctWords(Stream<String> lines) {
        return lines
                .flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct();
    }

    public static void main(String... args) {
        Stream<String> lines1 = null;
        Stream<String> lines2 = null;
        try {
            lines1 = getStreamFromFile();
            lines2 = getStreamFromFile();
            Stream<String> distinctWords1 = getDistinctWords(lines1);
            Stream<String> distinctWords2 = getDistinctWords(lines2);
            System.out.println("There are " + distinctWords1.count() + " distinct words in this file, here they are:");
            distinctWords2.forEach(System.out::println);
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } finally {
            lines1.close();
            lines2.close();
        }
    }

, но это все, что у меня осталось?

Ответы [ 3 ]

0 голосов
/ 27 мая 2018

Проблема на самом деле в том, что потоки не поддерживают на них несколько операций терминала, что является нежелательным ограничением.

Ближайшая альтернатива - это сбор обработанных данных в коллекцию и выполнение одних и тех же операций.:

List<String> distinctWords = getDistinctWords(lines1)
              .collect(Collectors.toList());

System.out.println("There are " + distinctWords.size() + 
        " distinct words in this file, here they are:");
distinctWords.forEach(System.out::println);

Другой подход заключается в использовании поведения с отслеживанием состояния, когда операции, выполняемые во время обхода потока, имеют побочные эффекты:

AtomicLong al = new AtomicLong();
getDistinctWords(lines1).forEach(string -> {
    al.incrementAndGet();
    System.out.println(string);
});

System.out.println("There are " + al.get() + 
        " distinct words in this file, here they are:");

Следует с осторожностью использовать поведение с сохранением состояния в потоках.Документация пакета java.util.stream содержит много информации об этом.Но я считаю, что в этом случае побочные эффекты не будут нежелательными.

0 голосов
/ 27 мая 2018

Вы не можете reset a Stream, но вы можете collect результаты ваших distinct();и вы также можете использовать \\s+ как регулярное выражение .Например,

static List<String> getDistinctWords(Stream<String> lines) {
    return lines.flatMap(line -> Arrays.stream(line.split("\\s+"))).distinct()
            .collect(Collectors.toList());
}

А затем измените ваш вызывающий абонент на

List<String> distinctWords = getDistinctWords(lines);
System.out.println("There are " + distinctWords.size() 
        + " distinct words in this file, here they are:");
distinctWords.forEach(System.out::println);

И вам не нужно так жестко кодировать пути, вы можете использовать системное свойство user.home, чтобы найти ваш файл,Мол,

return Files.lines(Paths.get(System.getProperty("user.home"), "Desktop/java.txt"));
0 голосов
/ 27 мая 2018

Вы не можете повторно использовать потоки.Просто соберите элементы в коллекцию, например List, или вызовите функцию (с состоянием), которая выводит каждый элемент, а также увеличивает счетчик.

...