Потоковая передача новых функций Java8 (базовая)

Java

предисловие

Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/bin39232820…
Лучшее время посадить дерево было десять лет назад, затем сейчас

болтовня

Сегодня начал писать серию новых фич Java 8. Как бы так сказать, в основном мало чего нового

  • Лямбда-выражения
  • функциональный интерфейс
  • ссылка на метод
  • Стрим поток
  • Необязательный класс
  • ключевое слово по умолчанию

Основные функции этих четырех — упростить написание кода, повысить производительность и т. д., но это также принесет хлопоты в обслуживании, потому что люди, которые в этом не разбираются, будут очень уставшими, но писать действительно вкусно. планирую поговорить о названии. Сегодня поговорим о нашем потоке Stream. Вы можете обратиться к следующим ссылкам для предыдущих разделов.
🔥Внутренние классы в Java, о которых вы не знали
🔥 Дженерики Java, которые вы должны знать
🔥Java8 новые функции лямбда-выражения, функциональный интерфейс, ссылка на метод и ключевое слово по умолчанию
🔥Необязательный класс новых функций Java8
Пока вы усердно учитесь, код, который вы будете писать в компании в будущем, будет нахальным, ха-ха. Гарантированно дебютирует в C-ранге

Что такое поток?

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

  • Элементы — это объекты определенного типа, образующие очередь. Потоки в Java не хранят элементы, а вычисляют по требованию.
  • Источник данных Источник потока. Может быть коллекцией, массивом, каналом ввода-вывода, генератором и т. д.
  • Операции агрегирования Операции, аналогичные операторам SQL, такие как фильтрация, сопоставление, сокращение, поиск, сопоставление, сортировка и т. д.

В отличие от предыдущих операций Collection, у операций Stream есть две основные характеристики:

  • Конвейерная обработка: Промежуточные операции возвращают сам объект потока. Таким образом, несколько операций могут быть объединены в конвейер, как в свободном стиле. Это позволяет оптимизировать такие операции, как ленивость и короткое замыкание.
  • Внутренняя итерация: ранее коллекция проходила через Iterator или For-Each, которые явно выполняли итерацию за пределами коллекции, что называлось внешней итерацией. Stream предоставляет внутренний метод итерации, который реализуется через шаблон посетителя (Visitor).

Особенности потока

  • Нет хранилища. Поток — это не структура данных, это просто представление какого-то источника данных, источником данных может быть массив, контейнер Java или канал ввода-вывода и т. д.

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

  • Ленивое исполнение. Операции над потоками выполняются не сразу, а только тогда, когда пользователю действительно нужен результат.

  • Расходуемость. Поток можно «использовать» только один раз, и он будет недействителен после его прохождения, точно так же, как итератор контейнера, он должен быть регенерирован, если его нужно пройти снова.

Давайте возьмем пример, чтобы увидеть, что может сделать Stream.

В приведенном выше примере возьмите несколько цветных пластиковых шариков в качестве источника данных, сначала отфильтруйте красные и расплавьте их в случайные треугольники. Снова профильтруйте и удалите маленькие треугольники. Наконец, вычислите периметр оставшейся фигуры.

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

Создание потока

Диаграмма классов, связанная с потоком

Вы можете найти все интерфейсы

Давайте снова посмотрим на коллекцию и обнаружим, что реализация этого интерфейса означает, что это значит? Указывает, что коллекции могут быть источником потоков, а также массивов и т. д.
Задать вопрос Может ли HashMap использовать потоки, давайте подумаем.

Создать поток из существующей коллекции

В Java 8, в дополнение к добавлению большого количества классов, связанных с потоком, также был улучшен сам класс коллекции, и был добавлен метод потока для преобразования класса коллекции в поток.

List<String> strings = Arrays.asList("六脉神剑", "六脉神剑1", "Hello", "HelloWorld", "六脉神剑2");
Stream<String> stream = strings.stream();

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

Этот метод создания потока через коллекцию также является более распространенным методом.

Создать поток из потока

Вы можете использовать методы, предоставляемые классом Stream, для прямого возврата потока, состоящего из указанных элементов.

метода

Stream<String> stream = Stream.of("六脉神剑", "六脉神剑1", "Hello", "HelloWorld", "六脉神剑2");

Как и в приведенном выше коде, создайте и верните поток непосредственно через метод of.

метод генератора (реже используется)

Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
    @Override
    public Double get() {
        return java.lang.Math.random();
    }
});

Stream<Double> generateB = Stream.generate(()-> java.lang.Math.random());
Stream<Double> generateC = Stream.generate(java.lang.Math::random);

Потоковые промежуточные операции (конвейерные промежуточные операции)

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

Ха-ха, когда дело доходит до блоггеров с конвейера, у меня есть глубокое понимание. Когда я учился в колледже, моя семья была бедной, и я ходил на работу во время летних каникул. То, что я делал, было сборочным конвейером. Продукт был разделен на десятки процессов, и каждый человек делал только один процесс, повторяя Да, я просто прикручивал кнопки магнитолы.Я прикручивал 10000 кнопок в день, и у меня были сломаны руки (потому что мне нужно было нажимать кнопки вниз, мне нужен был место, где я мог бы приложить силу, поэтому я использовал свой большой палец), а затем я использовал это Наклейте дюжину слоев клея на большой палец и продолжайте сушить на следующий день. Поэтому блогерам относительно просто понять работу этого пайплайна.

Ниже приведен список часто используемых промежуточных операций:

Давайте рассмотрим эти промежуточные операции одну за другой

filter

Метод filter используется для фильтрации элементов по заданным условиям (используется для фильтрации для получения нового потока). Следующий фрагмент кода использует метод filter для фильтрации пустых строк:

    public static void main(String[] args) {
        List<String> strings = Arrays.asList("六脉神剑", "", "大神", "小菜鸡", "交流群:549684836");
        strings.stream().filter(string -> !string.isEmpty()).forEach(System.out::println);
        //六脉神剑,大神 , 小菜鸡,交流群:549684836
    }

concat

Метод concat объединяет два потока вместе, чтобы сформировать один поток. Если оба входных потока отсортированы, новый поток также сортируется; если какой-либо из входных потоков является параллельным, новый поток также является параллельным; если новый поток закрыт, исходные два входных потока будут выполнять процесс отключения.

Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5))
       .forEach(integer -> System.out.print(integer + "  "));
// 1  2  3  4  5  

map

Метод map используется для сопоставления каждого элемента с соответствующим результатом.В следующем фрагменте кода карта используется для вывода числа в квадрате, соответствующего элементу:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().map( i -> i*i).forEach(System.out::println);
//9,4,4,9,49,9,25

Я буду говорить о карте внимательно, это более важно, давайте поговорим о ее понимании, то есть вы видите, что в карте есть функция, что это значит? Давайте посмотрим на исходный код. Вы помните, что означает Function? Я не помню, чтобы читал функциональное программирование, которое я написал ранее. Это означает передачу типа и возврат типа, то есть вы изначально являетесь потоком String, который может быть преобразован в Student. Поток классов или какая-либо другая форма потока. Вы можете превратить поток коллекции Streamf в Interge, это преобразование, что очень важно.

flatMap

Метод latMap похож на метод map тем, что он преобразует каждый элемент исходного Stream через функцию преобразования, разница в том, что объектом функции преобразования является Stream, и будет создан не новый Stream, а исходный Поток будет преобразован, элементы потока заменяются преобразованным потоком. Если поток, созданный функцией преобразования, равен нулю, его следует заменить пустым потоком. У flatMap есть три варианта примитивных типов: flatMapToInt, flatMapToLong и flatMapToDouble.

Stream.of(1, 2, 3)
    .flatMap(integer -> Stream.of(integer * 10))
    .forEach(System.out::println);
    // 10,20,30

Выражение, переданное в flatMap, принимает параметр типа Integer.Через функцию преобразования исходный элемент умножается на 10 для создания потока только с этим элементом, который заменяет элемент в исходном потоке.

peek

Метод peek генерирует новый поток, содержащий все элементы исходного потока, и предоставляет функцию потребления (экземпляр потребителя).Когда потребляется каждый элемент нового потока, заданная функция потребления будет выполняться, и функция потребления будет сначала выполнить, если нет. Это очень ясно, вы можете посмотреть на функцию Consumer, чтобы узнать

Stream.of(1, 2, 3, 4, 5)
        .peek(integer -> System.out.println("accept:" + integer))
        .forEach(System.out::println);
// accept:1
//  1
//  accept:2
//  2
//  accept:3
//  3
//  accept:4
//  4
//  accept:5
//  5

limit/skip

limit возвращает первые n элементов потока; skip отбрасывает первые n элементов. В следующем фрагменте кода используется метод limit для множителя 4 элементов:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().limit(4).forEach(System.out::println);
//3,2,2,3

sorted

Метод sorted используется для сортировки потока. В следующем фрагменте кода для сортировки используется метод sorted:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
//2,2,3,3,3,5,7

distinct

Different в основном используется для дедупликации.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
//3,2,7,5

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

код показывает, как показано ниже:

  public static void main(String[] args) {
        List<String> strings = Arrays.asList("六脉神剑",  "大神", "小菜鸡", "交流群:549684836");
        strings.stream().filter(string -> !string.isEmpty()).forEach(System.out::println);
        //六脉神剑,大神 , 小菜鸡,交流群:549684836
        Stream<Integer> distinct = strings.stream().filter(string -> string.length() <= 6).map(String::length).sorted().limit(2)
                .distinct();

    }

Нарисуйте картинку, чтобы все поняли, если рисунок не хороший, пожалуйста, простите меня.

Финальная операция потока

Результатом промежуточной операции Stream по-прежнему является Stream, так как же преобразовать Stream в нужный нам тип? Например, подсчет количества элементов в потоке, замена пакета потока набором и т. д. Для этого требуется терминальная операция

Последняя операция потребляет поток, производя окончательный результат. То есть после финальной операции поток нельзя использовать повторно, как и нельзя использовать какие-либо промежуточные операции, иначе будет выброшено исключение:

java.lang.IllegalStateException: stream has already been operated upon or closed

Общая окончательная операция выглядит следующим образом

forEach

Stream предоставляет метод forEach для перебора всех данных в потоке. Следующий фрагмент кода использует forEach для вывода 10 случайных чисел:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

count

count используется для подсчета количества элементов в потоке.

   List<String> strings = Arrays.asList("六脉神剑", "大神", "小菜鸡", "交流群:549684836");
      
        long count = strings.stream().filter(string -> string.length() <= 6).map(String::length).sorted().limit(2)
                .distinct().count();
        System.out.println(count);
        //2

collect

collect — это операция сокращения, которая принимает различные методы в качестве параметров для накопления элементов в потоке в итоговый результат:

   List<String> strings = Arrays.asList("六脉神剑", "大神", "小菜鸡", "交流群:549684836");

        List<Integer> collect = strings.stream().filter(string -> string.length() <= 6).map(String::length).sorted().limit(2)
                .distinct().collect(Collectors.toList());

Глядя на картинку выше, мы, наконец, получаем массив List, который является конечным пунктом назначения потока.

конец

Основы Stream почти закончены. Если вы можете следить за работой, вы, должно быть, вошли в дверь функционального программирования Stream. Завтра мы поговорим о расширенном использовании. Например, Collector должен быть не только тем, о чем мы только что говорили, но и тоже всемогущий. уменьшай, ок, увидимся завтра

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всеталант.

Творить нелегко. Ваша поддержка и признание — самая большая мотивация для моего творчества. Увидимся в следующей статье.

Six Meridians Excalibur | Text [Original] Если в этом блоге есть какие-то ошибки, прошу покритиковать и посоветовать, буду очень признателен!