Операции потоковых потоковых операций в Java8 - Начало работы

Java

Автор: Тан Юань

личный блог:javalover.cc

предисловие

Раньше его всегда называли друзья и друзья, и я почувствовал, что это почти подозрительно, поэтому позже я изменю имя для всех.

Поскольку все здесь для того, чтобы что-то увидеть, это призвано на время.ОфициальныйБар (вдохновленный одной из четырех известных классических произведений «Золотая ваза»)

Здравствуйте, чиновники, я Танъюань. Сегодня я представляю вам "Операцию потоковой передачи в Java8 - Введение", надеюсь, это поможет, спасибо

Статья чисто оригинальная, и личное резюме неизбежно ошибочно.Если есть, ответьте в области комментариев или личном сообщении в фоновом режиме, спасибо

Введение

Потоковые операции, также известные как функциональные операции, являются новой функцией Java 8.

Потоковые операции в основном используются для обработки данных (таких как коллекции), так же, как и генераторы в основном используются в коллекциях (кажется, что коллекции все еще очень важны, и они везде)

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

Сначала посмотрите каталог

содержание

  1. что такое стрим

  2. Босс, иди к каштану

  3. Шаги потока

  4. Характеристики потока

  5. Разница между потоковыми операциями и операциями сбора

текст

1. Что такое поток

Потоки — это API для манипулирования данными в декларативной манере.

Что такое декларативный способ?

Он только объявлен, а не реализован, как и абстрактные методы (полиморфизм).

2. Босс, принеси каштаны

举个栗子

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

нужно:фильтрКошки старше 1 года (1 год у кошек ≈ 5 лет у людей), увеличение по возрастуСортировать,наконецизвлекатьИмена хранятся отдельно в списке


public class BasicDemo {
    public static void main(String[] args) {
      // 以下猫的名字均为真名,非虚构
        List<Cat> list = Arrays.asList(new Cat(1, "tangyuan"), new Cat(3, "dangdang"), new Cat(2, "milu"));
        // === 旧代码 Java8之前 ===
        List<Cat> listTemp = new ArrayList<>();
        // 1. 筛选
        for(Cat cat: list){
            if(cat.getAge()>1){
                listTemp.add(cat);
            }
        }
        // 2. 排序
        listTemp.sort(new Comparator<Cat>() {
            @Override
            public int compare(Cat o1, Cat o2) {
                // 递增排序
                return Integer.compare(o1.getAge(), o2.getAge());
            }
        });
        // 3. 提取名字
        List<String> listName = new ArrayList<>();
        for(Cat cat: listTemp){
            listName.add(cat.getName());
        }
        System.out.println(listName);
        
        // === 新代码 Java8之后 ===
        List<String> listNameNew = list.stream()
          			// 函数式接口 Predicate的 boolean test(T t)抽象方法
                .filter(cat -> cat.getAge() > 1)
								// lambda表达式的方法引用
			          .sorted(Comparator.comparingInt(Cat::getAge))
          			// 函数式接口 Funtion的 R apply(T t)抽象方法
                .map(cat-> cat.getName())
             	  // 收集数据,把流转为集合List
                .collect(Collectors.toList());
        System.out.println(listNameNew);
    }
}
class Cat{
    int age;
    String name;

    public Cat(int age, String name) {
        this.age = age;
        this.name = name;
    }
	// 省略getter/setter
}

Как видите, с потоковыми операциями код намного проще (секунды вау)

В: Некоторые чиновники могут подумать, что это немного похоже на операцию комбинирования предыдущего лямбда-выражения.

A: Вы правы, это действительно похоже на то, что разница все еще очень большая. Поскольку операция объединения лямбда-выражений на самом деле является прямой операцией над множеством;

В конце статьи я расскажу о разнице между прямой операцией коллекций и потоковыми операциями, сначала пропустите здесь

Далее, на основе этого каштана, мы представим задействованные очки знаний.

3. Этапы работы потока

Давайте проигнорируем старую версию операции множества (мы поговорим о разнице между потоком и множеством позже), давайте сначала введем операцию потока (в конце концов, поток — главный герой сегодняшнего дня)

主角

Потоковые операции делятся на три этапа: создание потоков, промежуточные операции и терминальные операции.

Процесс выглядит следующим образом:

流的操作流程

Здесь мы должны обратить внимание на очень важный момент:

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

Вы можете представить, что описанный выше процесс — это конвейер: давайте упростим его здесь.

  1. Цель: Позвольте мне сначала сказать вам, что мы собираемся обрабатывать бутилированную воду (сначала создайте поток и сообщите, какие данные обрабатывать)
  2. Затем построить сборочную линию для этих бутылок и воды: приспособления для крепления бутылок, водопроводные трубы для воды, захваты для завинчивания крышек, упаковщики для бокса (промежуточные операции, декларирование операций, которые необходимо выполнить)
  3. Наконец, нажмите кнопку запуска, конвейер начинает работать (терминальная операция, начинает обрабатывать данные в соответствии с промежуточной операцией)

流水线

Потому что каждая промежуточная операция возвращает поток (Stream), поэтому их можно комбинировать все время (кажется, что-то съел?), но порядок их комбинаций не фиксирован, и поток будет выбираться по производительности системы.

Мы можем распечатать что-нибудь, чтобы увидеть:

List<Cat> list = Arrays.asList(new Cat(1, "tangyuan"), new Cat(3, "dangdang"), new Cat(2, "milu"));
List<String> listNameNew = list.stream()
  .filter(cat -> {
    System.out.println("filter: " + cat);
    return cat.getAge() > 1;
  })
  .map(cat-> {
    System.out.println("map:" + cat);
    return cat.getName();
  })
  .collect(Collectors.toList());

Результат выглядит следующим образом:

filter: Cat{age=1}
filter: Cat{age=3}
map:Cat{age=3}
filter: Cat{age=2}
map:Cat{age=2}

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

Это слияние в основном определяется самой потоковой операцией на основе производительности системы.

Поскольку было сказанослияние циклов, то пройти дальшеНавыки короткого замыкания

Слово короткое замыкание должно быть всем знакомо (например, короткое замыкание в мозгу), что означает, что изначально должно выполняться A->B->C, но оно замыкается на B, поэтому становится A->C

Короткое замыкание здесь относится к промежуточной операции.По некоторым причинам (например, ограничение ниже) выполняется только часть, но не все.

Давайте изменим приведенный выше пример (с промежуточным лимитом операций):

List<Cat> list = Arrays.asList(new Cat(1, "tangyuan"), new Cat(3, "dangdang"), new Cat(2, "milu"));
List<String> listNameNew = list.stream()
  .filter(cat -> {
    System.out.println("filter: " + cat);
    return cat.getAge() > 1;
  })
  .map(cat-> {
    System.out.println("map:" + cat);
    return cat.getName();
  })
  // 只加了这一行
  .limit(1)
  .collect(Collectors.toList());

Результат выглядит следующим образом:

filter: Cat{age=1}
filter: Cat{age=3}
map:Cat{age=3}

Как видите, из-за того, что limit(1) нужно толькоОдинэлемент, поэтому фильтрфильтр, просто найдисостояниеДа, это будетостановить фильтрациюоперации (последние элементы отбрасываются), этот прием называетсяНавыки короткого замыкания

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

4. Особенности потоков

Есть три особенности:

  • Декларативный: краткий, легко читаемый, со значительно сокращенным количеством строк кода (за исключением компаний, которым требуется ежедневная строка кода).
  • Composable: более гибкий, возможны различные комбинации (сколько хотите, пока это есть в потоке)
  • Распараллеливаемый: лучшая производительность (не нужно нам писать многопоточность, как приятно)

5. Разница между потоковыми операциями и операциями сбора:

Теперь давайте рассмотрим операции над множествами в первом примере: фильтровать -> сортировать -> извлекать.

List<Cat> listTemp = new ArrayList<>();
// 1. 筛选
for(Cat cat: list){
  if(cat.getAge()>1){
    listTemp.add(cat);
  }
}
// 2. 排序
listTemp.sort(new Comparator<Cat>() {
  @Override
  public int compare(Cat o1, Cat o2) {
    // 递增排序
    return Integer.compare(o1.getAge(), o2.getAge());
		/**
    * Q:为啥不用减法 return o1.getAge() - o2.getAge()?
    * A:因为减法会有数据溢出的风险
    * 	 如果o1.getAge()为20亿,o2.getAge()为-2亿,那么结果就会超过int的极限21亿多
    **/ 
  }
});
// 3. 提取名字
List<String> listName = new ArrayList<>();
for(Cat cat: listTemp){
  listName.add(cat.getName());
}
System.out.println(listName);

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

  1. В операции set есть временная переменная listTemp (без потоковой операции),
  2. Операция set всегда обрабатывала данные (в то время как потоковая операция не будет обрабатывать данные до терминальной операции на последнем шаге), фильтрация -> сортировка -> извлечение имен по порядку выполняется последовательно

Ниже мы используем таблицу для перечисления различий, которая должна быть интуитивно понятной.

Поток операций Установить операции
Функция обработка данных хранилище данных
Итеративный способ Внутренняя итерация (итерация только один раз), нужно только объявить, не нужно реализовывать, поток имеет свою реализацию) Внешняя итерация (ее можно повторять все время) требует собственного foreach
Обработка данных Фактическая обработка данных (по запросу) не начнется, пока не заработает терминал. обработка данных все время (все обработки)

Если для сравнения использовать пример из жизни, то можно использовать фильм как аналогию

Потоковое вещание похоже на просмотр онлайн, сбор — это локальный просмотр (локальная загрузка).

Суммировать

  1. Что такое поток:
    • Потоки — это API для манипулирования данными в декларативной манере.
    • поток поддерживается изоперации обработки данныхизисточникСгенерированопоследовательность элементов
      • Источник: источник данных, таких как коллекция, файл и т. Д. (Этот раздел представляет только эксплуатацию расхода коллекции, потому что более полезная; позже предъявляет другого)
      • Операция обработки данных: это промежуточная операция потока, такая как фильтр, карта
      • Последовательность элементов: через терминальную операцию потока возвращаемый набор результатов
  2. Процесс работы потока:
    • Создать поток -> Промежуточная операция -> Терминальная операция
    • Промежуточная операция является только оператором, фактически не обрабатывает данные и не будет выполняться до тех пор, пока не начнется терминальная операция.
  3. Объединение циклов: промежуточные операции будут свободно комбинироваться (поток определяет порядок объединения в соответствии с самой системой)
  4. Хитровой короткий замыкающий замыкает: если данные о обработке промежуточной работы достигли спроса, данные немедленно остановлены сразу (такие как предел (1) и остановят обработку при обработке 1
  5. Разница между потоковыми операциями и операциями сбора:
    • потокОбработка по требованию,собиратьполная обработка
    • основная атакаобработка данных, основная атакахранилище данных
    • потоклаконичный,собиратьНе делайте
    • потоквнутренняя итерация(Выполняется только один раз, после чего поток исчезнет), сборвнешняя итерация(можно повторять)

постскриптум

Наконец, спасибо всем за просмотр, спасибо

Оригинальность непростая, с нетерпением жду тройку чиновников