Узнайте о промежуточном порядке операций Java8 Stream.

Java

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

В прошлой статье рассказывалось о распространенных методах Stream, вы можете сначала ознакомиться с ней:Графический поток Java8, действительно ароматный

Вертикальное исполнение: карта и фильтр

Давайте посмотрим на следующий пример, найдем строку «b» в потоке и преобразуем ее в верхний регистр, включая две промежуточные операции.mapа такжеfilterи окончание операцииforEach.

Stream.of("a", "b", "c", "d", "e")
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("B");
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// 控制台输出
map: 	a
filter: A
map: 	b
filter: B
forEach: B
map: 	c
filter: C
map: 	d
filter: D
map: 	e
filter: E

Как видно из вывода, map/filter/forEachвертикальное исполнение, map и filter выполняются 5 раз, а forEach выполняется один раз.

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

Stream.of("a", "b", "c", "d", "e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// 控制台输出
filter: a
filter: b
map: 	b
forEach: B
filter: c
filter: d
filter: e

filter по-прежнему выполняется 5 раз, forEach выполняется один раз,Но карта уменьшена до 1 раза, то есть операция карты будет выполняться только в том случае, если фильтр соответствует фильтру.Этот метод работает быстрее, когда в потоке Stream большое количество элементов.

Горизонтальное исполнение: сортированное

Далее давайте посмотрим наsortedОперация сортировки, теперь обучение и продажа, мы ставим фильтр перед операцией карты:

Stream.of("d", "b", "c", "a", "e")
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + ", " + str2);
        return str1.compareTo(str2);
    })
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// 控制台输出
sorted: b, d
sorted: c, b
sorted: c, d
sorted: c, b
sorted: a, c
sorted: a, b
sorted: e, c
sorted: e, d
filter: a
filter: b
map: 	b
forEach: B
filter: c
filter: d
filter: e

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

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

Stream.of("d", "b", "c", "a", "e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b");
    })
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + ", " + str2);
        return str1.compareTo(str2);
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// 控制台输出
filter: d
filter: b
filter: c
filter: a
filter: e
map: 	b
forEach: B

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

Более того, sorted оказывает эффект усечения на вертикальное выполнение filter и map, то есть промежуточную операцию перед сортировкой необходимо полностью выполнить для формирования полного потока Stream, который передается sorted для сортировки.

Смешанное использование

Например, отфильтруйте «b» и «d», преобразуйте в верхний регистр и отсортируйте:

Stream.of("d", "b", "c", "a", "e")
    .filter(str -> {
        System.out.println("filter: " + str);
        return str.equals("b") || str.equals("d");
    })
    .map(str -> {
        System.out.println("map: \t" + str);
        return str.toUpperCase();
    })
    .sorted((str1, str2) -> {
        System.out.println("sorted: " + str1 + ", " + str2);
        return str1.compareTo(str2);
    })
    .forEach(str -> {
        System.out.println("forEach: " + str);
    });

// 控制台输出
filter: d
map: 	d
filter: b
map: 	b
filter: c
filter: a
filter: e
sorted: B, D
forEach: B
forEach: D

Из-за эффекта усечения sorted фильтр и карта выполняются вертикально, затем сортируются горизонтально и, наконец, forEach выполняется вертикально.

резюме

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

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

Оставьте вопрос: метод Stream.sorted, каков лежащий в его основе алгоритм сортировки? Добро пожаловать в область сообщений для обсуждения.