Эта статья поможет вам начать работу с Java Stream, который слишком силен.

Java

Две недели назад читатель настойчиво попросил меня написать статью о Java Stream. Я сказал, что их уже много на рынке. Угадайте, что он сказал: «Я просто хочу посмотреть, что вы написали! видишь, как бледно мне это нравится. Потом "неохотно" написать статью, хи-хи.

Одно только слово «Stream» кажется связанным с InputStream и OutputStream в пакете java.io. На самом деле, это не имеет значения. Новый Stream в Java 8 призван повысить производительность труда программистов при работе с коллекциями.Большая часть причин освобождения может быть связана с одновременным появлением лямбда-выражений, что значительно повышает эффективность программирования и доступность программ, читабельность.

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

Поток похож на расширенный итератор, но его можно пройти только один раз, как реку, текущую на восток; в процессе потока выполнять некоторые операции над элементами в потоке, такие как «отфильтровать строки длиной более 10» , "Получить первую букву каждой строки" и т.д.

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

Операции над потоками можно разделить на два типа:

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

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

Возьмем пример.

List<String> list = new ArrayList<>();
list.add("武汉加油");
list.add("中国加油");
list.add("世界加油");
list.add("世界加油");

long count = list.stream().distinct().count();
System.out.println(count);

distinct()Метод — это промежуточная операция (дедупликация), возвращающая новый поток (без общих элементов).

Stream<T> distinct();

count()Метод представляет собой терминальную операцию, которая возвращает количество элементов в потоке.

long count();

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

Теоретической части достаточно, перейдем непосредственно к собственно боевой части.

01. Создайте поток

Если это массив, вы можете использоватьArrays.stream()илиStream.of()Создайте поток; если это коллекция, вы можете использовать ее напрямуюstream()метод для создания потока, так как этот метод был добавлен в интерфейс коллекции.

public class CreateStreamDemo {
    public static void main(String[] args) {
        String[] arr = new String[]{"武汉加油", "中国加油", "世界加油"};
        Stream<String> stream = Arrays.stream(arr);

        stream = Stream.of("武汉加油", "中国加油", "世界加油");

        List<String> list = new ArrayList<>();
        list.add("武汉加油");
        list.add("中国加油");
        list.add("世界加油");
        stream = list.stream();
    }
}

Если вы посмотрите на исходный код Stream, вы найдетеof()Метод действительно вызываетArrays.stream()метод.

public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}

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

List<Long> aList = new ArrayList<>();
Stream<Long> parallelStream = aList.parallelStream();

02. Последовательность операций

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

1) Фильтр

пройти черезfilter()метод для фильтрации элементов, которые мы хотим из потока.

public class FilterStreamDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("周杰伦");
        list.add("王力宏");
        list.add("陶喆");
        list.add("林俊杰");
        Stream<String> stream = list.stream().filter(element -> element.contains("王"));
        stream.forEach(System.out::println);
    }
}

filter()Метод получает параметр типа Predicate (новый функциональный интерфейс в Java 8, который принимает входной параметр и возвращает логический результат), поэтому мы можем напрямую передать лямбда-выражение в метод, напримерelement -> element.contains("王")Это отфильтровать строку с «королем».

forEach()Метод получает параметр типа Consumer (добавленный в Java 8 функциональный интерфейс, который принимает входной параметр и не имеет операции возврата),类名 :: 方法名это новый синтаксис, представленный в Java 8,System.outВернитесь к классу PrintStream, метод println, который вы должны знать, это печать.

stream.forEach(System.out::println);Эквивалентно печати в цикле for, похожем на следующий код:

for (String s : strs) {
    System.out.println(s);
}

Очевидно, что одна строка кода выглядит лаконичнее. Взгляните на вывод программы:

王力宏

2) Отображение

Если вы хотите преобразовать элементы в потоке в элементы в новом потоке с помощью какой-либо операции, вы можете использоватьmap()метод.

public class MapStreamDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("周杰伦");
        list.add("王力宏");
        list.add("陶喆");
        list.add("林俊杰");
        Stream<Integer> stream = list.stream().map(String::length);
        stream.forEach(System.out::println);
    }
}

map()Метод получает параметр типа Function (новый функциональный интерфейс, добавленный в Java 8, который принимает входной параметр T и возвращает результат R), в этот раз параметр представляет собой метод длины класса String, то естьStream<String>течь вStream<Integer>поток.

Вывод программы следующий:

3
3
2
3

3) совпадать

Класс Stream предоставляет три метода сопоставления элементов:

  • anyMatch(), который возвращает true, если хотя бы один элемент соответствует переданному условию.

  • allMatch(), возвращает false, если только один элемент не соответствует переданному условию; возвращает true, если все совпадают.

  • noneMatch(), возвращает false, если хотя бы один элемент соответствует переданному условию; возвращает true, если все совпадают.

public class MatchStreamDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("周杰伦");
        list.add("王力宏");
        list.add("陶喆");
        list.add("林俊杰");

        boolean  anyMatchFlag = list.stream().anyMatch(element -> element.contains("王"));
        boolean  allMatchFlag = list.stream().allMatch(element -> element.length() > 1);
        boolean  noneMatchFlag = list.stream().noneMatch(element -> element.endsWith("沉"));
        System.out.println(anyMatchFlag);
        System.out.println(allMatchFlag);
        System.out.println(noneMatchFlag);
    }
}

Поскольку «Ван Лихом» начинается со слова «王», значение параметра anyMatchFlag должно быть истинным, поскольку длины строк «Джей Чжоу», «Ван Лихом», «Тао Чжэ» и «Цзюньцзе Линь» больше 1, поэтому allMatchFlag истинен, потому что 4 символа Ни одна из строк не заканчивается на «sink», поэтому noneMatchFlag истинен.

Вывод программы следующий:

true
true
true

4) Комбинация

reduce()Основная функция метода состоит в объединении элементов в Stream, его можно использовать двумя способами:

  • Optional<T> reduce(BinaryOperator<T> accumulator)

Начального значения нет, есть только один параметр, который является правилом операции, которое возвращается в это время.Optional.

  • T reduce(T identity, BinaryOperator<T> accumulator)

Есть начальное значение, правило операции и два параметра.В настоящее время возвращаемый тип совпадает с типом начального значения.

Взгляните на пример ниже.

public class ReduceStreamDemo {
    public static void main(String[] args) {
        Integer[] ints = {0, 1, 2, 3};
        List<Integer> list = Arrays.asList(ints);

        Optional<Integer> optional = list.stream().reduce((a, b) -> a + b);
        Optional<Integer> optional1 = list.stream().reduce(Integer::sum);
        System.out.println(optional.orElse(0));
        System.out.println(optional1.orElse(0));

        int reduce = list.stream().reduce(6, (a, b) -> a + b);
        System.out.println(reduce);
        int reduce1 = list.stream().reduce(6, Integer::sum);
        System.out.println(reduce1);
    }
}

Алгоритм может бытьЛямбда-выражения(Например(a, b) -> a + b) или classname::methodname (например,Integer::sum).

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

6
6
12
12

0, 1, 2 и 3 дают в сумме 6 без начального значения; с начальным значением 6 результат равен 12.

03. Поток конверсии

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

public class CollectStreamDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("周杰伦");
        list.add("王力宏");
        list.add("陶喆");
        list.add("林俊杰");

        String[] strArray = list.stream().toArray(String[]::new);
        System.out.println(Arrays.toString(strArray));

        List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());
        List<String> list2 = list.stream().collect(Collectors.toCollection(ArrayList::new));
        System.out.println(list1);
        System.out.println(list2);

        String str = list.stream().collect(Collectors.joining(", ")).toString();
        System.out.println(str);
    }
}

toArray()Метод может преобразовать поток в массив, вам может быть интереснееString[]::new, что это? посмотриtoArray()Исходный код метода.

<A> A[] toArray(IntFunction<A[]> generator);

то естьString[]::newявляется IntFunction, функцией, которая создает желаемый новый массив, который можно декомпилировать байт-кодом, чтобы увидеть, что это такое:

String[] strArray = (String[])list.stream().toArray((x$0) -> {
    return new String[x$0];
});
System.out.println(Arrays.toString(strArray));

То есть это эквивалентно возврату массива строк заданной длины.

Когда нам нужно преобразовать набор в другой набор по определенным правилам, мы можем использовать его вместеmap()Методы иcollect()метод.

List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());

пройти черезstream()После того, как метод создаст поток коллекции, затем передайтеmap(String:length)сопоставьте его с новым потоком длин строк и, наконец, передайтеcollect()метод для преобразования его в новую коллекцию.

Collectors — это класс инструментов для сборщиков с рядом встроенных реализаций сборщиков, таких какtoList()способ собрать элементы в новыйjava.util.Listв; напримерtoCollection()способ собрать элементы в новыйjava.util.ArrayListв; напримерjoining()собирает элементы в строку, которую можно указать с помощью разделителя.

Взгляните на вывод программы:

[周杰伦, 王力宏, 陶喆, 林俊杰]
[3, 3, 2, 3]
[周杰伦, 王力宏, 陶喆, 林俊杰]
周杰伦, 王力宏, 陶喆, 林俊杰

04. Спасибо

Что ж, мои дорогие читатели и друзья, вышеизложенное и есть все содержание этой статьи, не кажется ли вам, что Stream слишком мощный? Я Silent King Er, интересный программист.Оригинальность непроста, не просите пустой билет, пожалуйста, поставьте лайк этой статье, что будет моей сильнейшей мотивацией писать больше качественных статей.

Если вы считаете, что статья немного полезна для вас, пожалуйста, выполните поиск по запросу "Тихий король 2"Прочтите это в первый раз, ответьте [666] Есть также обучающие видео высокой четкости 500G (по категориям), которые я тщательно подготовил для вас. Эта статья GitHubОн был включен, и есть полные тестовые площадки для интервью на крупных заводах Добро пожаловать в Star.