Автор: Тан Юань
личный блог:javalover.cc
предисловие
Раньше его всегда называли друзья и друзья, и я почувствовал, что это почти подозрительно, поэтому позже я изменю имя для всех.
Поскольку все здесь для того, чтобы что-то увидеть, это призвано на время.ОфициальныйБар (вдохновленный одной из четырех известных классических произведений «Золотая ваза»)
Здравствуйте, чиновники, я Танъюань. Сегодня я представляю вам "Операцию потоковой передачи в Java8 - Введение", надеюсь, это поможет, спасибо
Статья чисто оригинальная, и личное резюме неизбежно ошибочно.Если есть, ответьте в области комментариев или личном сообщении в фоновом режиме, спасибо
Введение
Потоковые операции, также известные как функциональные операции, являются новой функцией Java 8.
Потоковые операции в основном используются для обработки данных (таких как коллекции), так же, как и генераторы в основном используются в коллекциях (кажется, что коллекции все еще очень важны, и они везде)
Ниже мы в основном используем примеры для ознакомления с базовой операцией потока (рекомендуется сначала ознакомиться с ней).лямбда-выражения, описанный влямбда-выражение,функциональный интерфейс,ссылка на методподождите, он будет использован ниже)
Сначала посмотрите каталог
содержание
-
что такое стрим
-
Босс, иди к каштану
-
Шаги потока
-
Характеристики потока
-
Разница между потоковыми операциями и операциями сбора
текст
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. Этапы работы потока
Давайте проигнорируем старую версию операции множества (мы поговорим о разнице между потоком и множеством позже), давайте сначала введем операцию потока (в конце концов, поток — главный герой сегодняшнего дня)
Потоковые операции делятся на три этапа: создание потоков, промежуточные операции и терминальные операции.
Процесс выглядит следующим образом:
Здесь мы должны обратить внимание на очень важный момент:
Промежуточная операция не выполняет никакой обработки до тех пор, пока не начнется терминальная операция, она просто объявляет, что делать;
Вы можете представить, что описанный выше процесс — это конвейер: давайте упростим его здесь.
- Цель: Позвольте мне сначала сказать вам, что мы собираемся обрабатывать бутилированную воду (сначала создайте поток и сообщите, какие данные обрабатывать)
- Затем построить сборочную линию для этих бутылок и воды: приспособления для крепления бутылок, водопроводные трубы для воды, захваты для завинчивания крышек, упаковщики для бокса (промежуточные операции, декларирование операций, которые необходимо выполнить)
- Наконец, нажмите кнопку запуска, конвейер начинает работать (терминальная операция, начинает обрабатывать данные в соответствии с промежуточной операцией)
Потому что каждая промежуточная операция возвращает поток (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);
Вы можете видеть, что есть два момента, которые отличаются от потоковых операций:
- В операции set есть временная переменная listTemp (без потоковой операции),
- Операция set всегда обрабатывала данные (в то время как потоковая операция не будет обрабатывать данные до терминальной операции на последнем шаге), фильтрация -> сортировка -> извлечение имен по порядку выполняется последовательно
Ниже мы используем таблицу для перечисления различий, которая должна быть интуитивно понятной.
Поток операций | Установить операции | |
---|---|---|
Функция | обработка данных | хранилище данных |
Итеративный способ | Внутренняя итерация (итерация только один раз), нужно только объявить, не нужно реализовывать, поток имеет свою реализацию) | Внешняя итерация (ее можно повторять все время) требует собственного foreach |
Обработка данных | Фактическая обработка данных (по запросу) не начнется, пока не заработает терминал. | обработка данных все время (все обработки) |
Если для сравнения использовать пример из жизни, то можно использовать фильм как аналогию
Потоковое вещание похоже на просмотр онлайн, сбор — это локальный просмотр (локальная загрузка).
Суммировать
- Что такое поток:
- Потоки — это API для манипулирования данными в декларативной манере.
- поток поддерживается изоперации обработки данныхизисточникСгенерированопоследовательность элементов
- Источник: источник данных, таких как коллекция, файл и т. Д. (Этот раздел представляет только эксплуатацию расхода коллекции, потому что более полезная; позже предъявляет другого)
- Операция обработки данных: это промежуточная операция потока, такая как фильтр, карта
- Последовательность элементов: через терминальную операцию потока возвращаемый набор результатов
- Процесс работы потока:
- Создать поток -> Промежуточная операция -> Терминальная операция
- Промежуточная операция является только оператором, фактически не обрабатывает данные и не будет выполняться до тех пор, пока не начнется терминальная операция.
- Объединение циклов: промежуточные операции будут свободно комбинироваться (поток определяет порядок объединения в соответствии с самой системой)
- Хитровой короткий замыкающий замыкает: если данные о обработке промежуточной работы достигли спроса, данные немедленно остановлены сразу (такие как предел (1) и остановят обработку при обработке 1
- Разница между потоковыми операциями и операциями сбора:
- потокОбработка по требованию,собиратьполная обработка
- основная атакаобработка данных, основная атакахранилище данных
- потоклаконичный,собиратьНе делайте
- потоквнутренняя итерация(Выполняется только один раз, после чего поток исчезнет), сборвнешняя итерация(можно повторять)
постскриптум
Наконец, спасибо всем за просмотр, спасибо
Оригинальность непростая, с нетерпением жду тройку чиновников