Рубрики
Без рубрики

Эффективная Java! Используйте Поток Разумно

Погружение в главу 44 эффективной Java. С тегами java, effective, streams, architecture.

Сегодня мы рассмотрим концепцию потоков. Потоки – это еще одна отличная функция, добавленная в Java 8, которая позволяет создавать более декларативный и лаконичный код. Потоки содержат две две абстракции: поток , который представляет конечную или бесконечную группу элементов, и конвейер потока , который представляет многоступенчатую систему вычислений.

Другими словами, потоки содержат источник , обрабатывающие узлы и терминальную операцию . Источником может быть любое количество вещей, таких как коллекция, содержимое файла, генераторы случайных чисел и сами другие потоки. Узлы обработки – это любое количество узлов обработки, которые могут манипулировать данными и воздействовать на них, прежде чем передавать их следующему узлу. Наконец, есть терминальный узел. Именно здесь на самом деле происходит действие. Именно здесь все обработанные товары попадают в конечный пункт назначения. Этот терминальный узел может собирать в коллекцию или обрабатывать каждый элемент по отдельности, например. Следует отметить, что все потоковые операции (кроме терминального узла) обрабатываются лениво . Это означает, что записи будут эффективно проходить через каждый промежуточный узел обработки вплоть до конечного узла. Терминальный узел будет извлекать только столько элементов, сколько ему необходимо. Это означает, что если вы не поместите терминальный узел в потоковый конвейер, через него вообще ничего не будет обрабатываться.

Хватит разговоров, давайте рассмотрим пример, сначала без использования потоков. Эта программа обрабатывает словарь терминов и предоставит анаграммы в этом словаре определенной длины.

public class Anagram {
  public static void main(String[] args) throws IOException {
    File dictionary = new File(args[0]);
    int minGroupSize = Integer.parseInt(args[1]);
    Map> groups = new HashMap<>();
    try(Scanner s = new Scanner(dictionary)) {
      while(s.hasNext()) {
        String word = s.next();
        groups.computeIfAbsent(alphabetize(word), (unused) -> new TreeSet<>()).add(word);
      }
    }
    for (Set group : groups.values()) {
      if (group.size() >= minGroupSize) {
        System.out.println(group.size() + ":" + group);
      }
    }
  }

  private static String alphabetize(String s) {
    char[] a = s.toCharArray();
    Arrays.sort(a);
    return new String(a);
  }
}

Эта программа будет работать нормально. Давайте теперь рассмотрим потоковую версию:

public class Anagrams {
  public static void main(String[] args) throws IOException {
    Path dictionary = Paths.get(args[0]);
    int minGroupSize = Integer.parseInt(args[1]);

    try (Stream words = Files.lines(dictionary)) {
      words.collect(groupingBy(word -> alphabetize(word)))
        .values().stream()
        .filter(group -> group.size() >= minGroupSize)
        .forEach(g -> System.out.println(g.size() + ":" + g));
    }
  }

  // alphabetize method is the same.
}

В приведенном выше примере мы получаем некоторые большие преимущества простоты при использовании потоков. Мы могли бы пойти дальше но в тот момент мы, скорее всего, снизили бы читаемость. Это искусство, которому вы должны научиться с помощью потоков. Используя его для упрощения вашего кода, а не для того, чтобы сделать его хуже, как и все хорошие вещи, это может зайти слишком далеко.

Давайте перечислим некоторые другие вещи, которые следует иметь в виду при работе с лямбдами и потоками.

  • Поскольку явных типов не существует, имена параметров для лямбд еще более необходимы.
  • Чтобы улучшить удобочитаемость, лучше всего использовать вспомогательные методы для использования в ваших потоках.
  • Надеюсь, это само собой разумеется, но используйте streams только в том случае, если это улучшает код и не делает его более нечитаемым.

Я большой поклонник стримов. К ним может потребоваться некоторое привыкание, но как только вы их поймете, я стану их большим поклонником. Это не только делает ваш код более кратким, но и позволяет вам сфокусировать свой код в более декларативной манере, сосредоточив внимание на том, чего вы хотите достичь, а не на том, как это сделать.

Оригинал: “https://dev.to/kylec32/effective-java-use-stream-judiciously-4178”