一、Java SE8 的流库

1、从迭代到流的操作

流表面上看起来和集合很类似,都可以让我们转换和获取数据。但是,它们之间存在着显著的差异:
1.流并不存储其元素。这些元素可能存储在底层的集合中,或者是按需生成的。
2.流的操作不会修改其数据源。例如,filter方法不会从新的流中移除元素,而是会生成一个新的流,其中不包含被过滤掉的元素。
3.流的操作是尽可能惰性执行的。这意味着直至需要其结果时,操作才会执行。

流是用stream或parallelStream方法创建的。filter方法对其进行转换,而count方法是终止操作。

示例代码:

public class CountLongWords {
    public static void main(String[] args) throws IOException {
        String contents = new String(Files.readAllBytes(Paths.get("D:\\个人\\demo.txt")), StandardCharsets.UTF_8);
        List<String> words = Arrays.asList(contents.split("\\PL+"));

        long count = 0;
        for (String word : words){
            if (word.length() > 7){
                count ++;
            }
        }
        System.out.println(count); //1

        count = words.stream().filter(v -> v.length() > 7).count();
        System.out.println(count); //1

        count = words.parallelStream().filter(v -> v.length() > 7).count();
        System.out.println(count); //1
    }
}

2、流的创建

Collection接口的stream方法将任何集合转换为一个流。如果你有一个数组,可以使用静态的Stream.of方法;
还可以使用Array.stream(array, from, to)从数组中位于from(包括)和to(不包括)的元素中创建一个流。
为了创建不包含任何元素的流,可以使用静态的Stream.empty()方法;
获取一个常量值的流:Stream<String> echos = Stream.generate(() -> "Echo");
获取一个随机数的流:Stream<Double> randoms= Stream.generate(Math::random);
获取一个无限序列的流:Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));

示例代码:

package com.java02.day01.streams;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.regex.Pattern.*;

/**
 * @author: juju
 * @date: 2020-06-22 16:10
 */
public class CreatingStreams {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("D:\\\\个人\\\\demo.txt");
        String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
        Stream<String> words = Stream.of(contents.split("\\PL+"));
        show("words", words);
        Stream<String> song = Stream.of("Linda", "Bo", "Alice", "Selina");
        show("song", song);
        Stream<Object> empty = Stream.empty();
        show("empty", empty);
        Stream<String> echos = Stream.generate(() -> "Echo");
        show("echos", echos);
        Stream<Double> random = Stream.generate(Math::random);
        show("random", random);
        Stream<BigInteger> iterate = Stream.iterate(BigInteger.ONE, i -> i.add(BigInteger.ONE));
        show("iterate", iterate);
        Stream<String> wordsAntherWay = compile("\\PL+").splitAsStream(contents);
        show("wordsAntherWay", wordsAntherWay);
        Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
        show("lines", lines);
    }

    private static <T> void show(String title, Stream<T> stream){
        final int SIZE = 10;
        List<T> firstElements = stream.limit(SIZE + 1).collect(Collectors.toList());
        System.out.print(title + ":");
        for (int i = 0; i< firstElements.size(); i++){
            if (i > 0){
                System.out.print(",");
            }
            if (i < SIZE){
                System.out.print(firstElements.get(i));
            }else {
                System.out.print("...");
            }
        }
        System.out.println();
    }
}

执行结果:
在这里插入图片描述

3、filter、map和flatMap方法

流的转换会产生一个新的流,它的元素派生自另一个流中的元素。filter转换会产生一个流Stream<String> words = words.stream().filter(v -> v.length() > 7);
通常我们想要按照某种方式来转换流中的值,此时,可以使用map方法并传递执行该转换的函数。Stream<String> lowercaseWords = words.stream().map(String::toLowerCase);
Stream<String> firstLetters = words.stream().map(s -> s.substring(0,1));

4、抽取子流和连接流

调用stream.limit(n)会返回一个新的流,它在n个元素之后结束。Stream<Double> randoms = Stream.generate(Math::random).limit(100);
调用stream.skip(n)正好相反,它会丢弃前n个元素;
调用Stream类的静态的concat方法将两个流连接起来;

5、其他的流转换

distinct方法会返回一个流,它的元素是从原有流中产生的。即原来的元素按照同样的顺序剔除重复元素后产生的。Stream.of("merrily", "merrily", "merrily", "gently").distinct();
对于流的排序,有多种sorted方法的变体可用。words.stream().sorted(Comparator.comparing(String::length).reversed());
peek方法会产生另一个流,它的元素与原来流中的元素相同,但是在每次获取一个元素时,都会调用一个函数。

6、简单约简

约简是一种终结操作,它们会将流约简为可以在程序中使用的非流值。

count方法就是一种简单约简,它会返回流中元素的数量。
其他的简单约简还有max和min,它们会返回最大值和最小值,这些方法返回的是一个类型Optional< T>的值。

7、Optional类型

7.1 如何使用Optional值

使用某种默认值,可能是空字符串:String result = optionalString.orElse(" ");
可以调用代码来计算默认值:String result = optionalString.orElseGet(() -> Locale.getDefault().getDisplayName());
可以在没有任何值时抛出异常:String result = optionalString.orElseThrow(IllegalStateException::new);

ifPresent方法会接受一个函数。如果该可选值存在,那么它会被传递给该函数。否则,不会发生任何事情。optionValue.ifPresent(v -> Process v);
当调用ifPresent时,从该函数不会返回任何值。如果想要处理函数的结果,应该使用map:Optional<Boolean> added = optionalValue.map(results::add);

7.2 创建Optional值

创建Optional值,可以使用Optional.of(result)和Optional.empty()。

public static Optional<Doublt> inverse(Double x){
	return x == 0? Optional.empty() : Optional.of(1/x);
}

ofNullable方法被用来作为可能出现的null值和可选值之间的桥梁。Optional.ofNullable(obj)会在obj不为null的情况下返回Optional.of(obj),否则会返回Optional.empty()。

flatMap() 产生将mapper应用于当前Optional值所产生的结果,或者再当前Optional为空时,返回一个空Optional。

示例代码:

package com.java02.day01.optional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-23 10:33
 */
public class OptionalTest {
    public static void main(String[] args) throws IOException {
        String contents = new String(Files.readAllBytes(Paths.get("D:\\个人\\demo.txt")), StandardCharsets.UTF_8);
        List<String> wordList = Arrays.asList(contents.split("\\PL+"));
        Optional<String> optionalValue = wordList.stream().filter(v -> v.contains("happy")).findFirst();
        System.out.println(optionalValue.orElse("no word") + " contains happy");
        //happy contains happy

        Optional<String> empty = Optional.empty();
        String result = empty.orElse("N/A");
        System.out.println("result: " + result);
        //result: N/A
        
        try {
            result = empty.orElseThrow(IllegalStateException::new);
            System.out.println("result: " + result);
        } catch (IllegalStateException e) {
            e.printStackTrace();
            //java.lang.IllegalStateException
            //	at java.util.Optional.orElseThrow(Optional.java:290)
            //	at com.java02.day01.optional.OptionalTest.main(OptionalTest.java:26)
        }

        optionalValue = wordList.stream().filter(v -> v.contains("birthday")).findFirst();
        optionalValue.ifPresent(v -> System.out.println(v + " contains birthday"));
        //birthday contains birthday
        System.out.println(optionalValue);
        //Optional[birthday]

        Set<String> results = new HashSet<>();
        optionalValue.ifPresent(results :: add);
        System.out.println(results);
        //[birthday]
        Optional<Boolean> adds = optionalValue.map(results::add);
        System.out.println(adds);
        //Optional[false]
        System.out.println(results);
        //[birthday]
        
        System.out.println(inverse(4.0).flatMap(OptionalTest::squareRoot));
        //Optional[0.5]
        System.out.println(inverse(-1.0).flatMap(OptionalTest::squareRoot));
        //Optional.empty
        System.out.println(inverse(0.0).flatMap(OptionalTest::squareRoot));
        //Optional.empty
        Optional<Double> aDouble = Optional.of(-4.0).flatMap(OptionalTest::inverse).flatMap(OptionalTest::squareRoot);
        System.out.println(aDouble);
        //Optional.empty
    }

    private static Optional<Double> inverse(Double x){
        return x == 0 ? Optional.empty() : Optional.of(1/x);
    }

    private static Optional<Double> squareRoot(Double x){
        return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
    }
}

8、收集结果

当处理完流之后,通常会想要查看其元素。可以调用forEach方法,将某个函数应用于每个元素:stream.forEach(System.out::println);
将结果收集到数据结构中:
String[] result = stream.toArray(String[] :: new);
List<String> result = stream.collect(Collectors.toList());
Set<String> result = stream.collect(Collectors.toSet());
Set<String> result = stream.collect(Collectors.toCollection(TreeSet::new));

如果想要将流的结果约简为总和、平均值、最大值或最小值,可以使用summarizing(Int|Long|Double)方法中的某一个。

IntSummaryStatistics summary = stream.collect(Collectors.summarizingInt(String :: length));
double averageWordLength = summary.getAverage();
double maxWordLength = summary.getMax();

示例代码:

package com.java02.day01.collecting;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-23 11:17
 */
public class CollectingResults {
    public static void main(String[] args) throws IOException {
        Iterator<Integer> iter = Stream.iterate(0, v -> v + 1).limit(10).iterator();
        while (iter.hasNext()){
            System.out.print(iter.next() + ", ");
            //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
        }
        System.out.println();

        Object[] numbers = Stream.iterate(0, v -> v + 1).limit(10).toArray();
        System.out.println("Object Array: " + Arrays.toString(numbers));
        //Object Array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

        try {
            Integer number = (Integer) numbers[0];
            System.out.println("number: " +  number);
            //number: 0
            System.out.println("the following statement throws an exception: ");
            Integer[] numbers2 = (Integer[]) numbers;
            //java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
            //	at com.java02.day01.collecting.CollectingResults.main(CollectingResults.java:33)
        } catch (Exception e) {
            e.printStackTrace();
        }

        Integer[] numbers3 = Stream.iterate(0, v -> v + 1).limit(10).toArray(Integer[]::new);
        System.out.println("Integer Array: " + numbers3[3]);
        //Integer Array: 3

        Set<String> noVowelSet = noVowel().collect(Collectors.toSet());
        show("noVowelSet", noVowelSet);
        //noVowelSet: java.util.HashSet
        //[ , birthday, new, Happy, year, to, Chrisermes, lalala, every, day]

        TreeSet<String> noVowelTreeSet = noVowel().collect(Collectors.toCollection(TreeSet::new));
        show("noVowelTreeSet", noVowelTreeSet);
        //noVowelTreeSet: java.util.TreeSet
        //[ , Chrisermes, Happy, Marry, birthday, day, every, lalala, new, to]

        String result = noVowel().limit(10).collect(Collectors.joining());
        System.out.println("Joining: " + result);
        //Joining:  birthdaytoyou newyearHappyMarryChrisermes
        result = noVowel().limit(10).collect(Collectors.joining(", "));
        System.out.println("Joining with commas: " + result);
        //Joining with commas:  , birthday, to, you,  , new, year, Happy, Marry, Chrisermes

        IntSummaryStatistics summary = noVowel().collect(Collectors.summarizingInt(String::length));
        double average = summary.getAverage();
        int max = summary.getMax();
        System.out.println("average words length: " + average);
        //average words length: 4.071428571428571
        System.out.println("max words length: " + max);
        //max words length: 10
        System.out.print("forEach: ");
        noVowel().limit(10).forEach(System.out::print);
        //forEach:  birthdaytoyou newyearHappyMarryChrisermes
        System.out.println();

    }

    public static Stream<String> noVowel() throws IOException {
        String contents = new String(Files.readAllBytes(Paths.get("D:\\个人\\demo.txt")), StandardCharsets.UTF_8);
        List<String> wordList = Arrays.asList(contents.split("\\PL+"));
        Stream<String> words = wordList.stream();
        return words.map(v -> v.replaceAll("happy", " "));
    }

    public static <T> void show(String label, Set<T> set){
        System.out.println(label + ": " +  set.getClass().getName());
        System.out.println("[" +
                set.stream().limit(10).map(Objects::toString).collect(Collectors.joining(", "))
                + "]");
    }
}

9、收集到映射表中

示例代码:

package com.java02.day01.collecting;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-23 14:50
 */
public class Person {
    private int id;
    private String name;

    public Person() {
    }

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

package com.java02.day01.collecting;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-23 14:48
 */
public class CollectingIntoMaps {
    public static Stream<Person> people(){
        return Stream.of(new Person(1002, "Lily"), new Person(1008, "Alice"), new Person(1005, "Cindy"));
    }

    public static void main(String[] args){
        Map<Integer, String> idToName = people().collect(Collectors.toMap(Person::getId, Person::getName));
        System.out.println("idToName: " + idToName);
        //idToName: {1008=Alice, 1002=Lily, 1005=Cindy}
        Map<Integer, Person> idToPerson = people().collect(Collectors.toMap(Person::getId, Function.identity()));
        System.out.println("idToPerson: " + idToPerson.getClass().getName() + idToPerson);
        //idToPerson: java.util.HashMap{1008=Person{id=1008, name='Alice'}, 1002=Person{id=1002, name='Lily'}, 1005=Person{id=1005, name='Cindy'}}

        idToPerson = people().collect(Collectors.toMap(Person::getId, Function.identity(),
                (existingValue, newValue) -> { throw new IllegalStateException();}, TreeMap::new));
        System.out.println("idToPerson: " + idToPerson.getClass().getName() + idToPerson);
        //idToPerson: java.util.TreeMap{1002=Person{id=1002, name='Lily'}, 1005=Person{id=1005, name='Cindy'}, 1008=Person{id=1008, name='Alice'}}

        Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
        Map<String, String> languageNames = locales.collect(Collectors.toMap(Locale::getDisplayLanguage, v -> v.getDisplayCountry(v),
                (existingValue, newValue) -> existingValue));
        System.out.println("languageNames: " + languageNames);
        //languageNames: {土耳其文=, =, 意大利文=, 冰岛文=Ísland, 印地文=भारत, 马其顿文=, 乌克兰文=, 立陶宛文=, 越南文=Việt Nam, 俄文=Россия, ...

        locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<String>> countryLanguageSet = locales.collect(Collectors.toMap(Locale::getDisplayCountry,
                v -> Collections.singleton(v.getDisplayLanguage()),
                (a, b) -> {
                    Set<String> union = new HashSet<>(a);
                    union.addAll(b);
                    return union;
                }));
        System.out.println("countryLanguageSet: " + countryLanguageSet);
        //countryLanguageSet: {泰国=[泰文], 巴西=[葡萄牙文], =[, 土耳其文, 意大利文, 冰岛文, 印地文, 乌克兰文, 马其顿文, 立陶宛文, 越南文, 俄文, ...
    }
}

10、群组和分区

将具有相同特性的值群聚成组是非常常见的,并且groupingBy方法直接就支持它。Map<String, List<Locale>> countryToLocales = locals.collect(Collectors.groupingBy(Locale::getCountry));
当分类函数是断言函数时(即返回boolean值的函数),流的元素可以分区为两个列表:该函数返回true的元素和其他的元素。在这种情况下,使用partitioningBy比使用groupingBy要更高效。

11、下游收集器

groupingBy方法会产生一个映射表,它的每个值都是一个列表。如果想要以某种方式来处理这些列表,就需要提供一个“下游收集器”。例如,如果想要获得集而不是列表,那么可以使用上一节中看到的Collector.toSet收集器:locales.collect(groupingBy(Locale::getCountry, toSet()));

counting会产生手机到的元素的个数,例如:Map<String, Long> countryToLocaleCounts = locales.collect(groupingBy(Locale::getCountry, counting()));
summing(Int|Long|Double)会接受一个函数作为引元,将该函数应用到下游元素中,并产生它们的和。例如:Map<String, Integer> stateToCityPopulation = cities.collect(groupingBy(City::getState, summingInt(City::getPopulation)));
maxBy和minBy会接受一个比较器,并产生下游元素中的最大值和最小值。
mapping方法会产生将函数应用到下游结果上的收集器,并将函数值传递给另一个收集器。

示例代码:

package com.java02.day01.collecting;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-23 16:36
 */
public class DownStreamCollectors {
    public static void main(String[] args) throws IOException {
        Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<Locale>> countryToLocaleSet = locales.collect(groupingBy(Locale::getCountry, toSet()));
        System.out.println("countryToLocaleSet: " + countryToLocaleSet);

        locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Long> countryToLocaleCount = locales.collect(groupingBy(Locale::getCountry, counting()));
        System.out.println("countryToLocaleCount: " + countryToLocaleCount);

        Stream<City> cities = readCities("D:\\个人\\cities.txt");
        Map<String, IntSummaryStatistics> stateToCityPopulation = cities.collect(groupingBy(City::getState, summarizingInt(City::getPopulation)));
        System.out.println("stateToCityPopulation: " + stateToCityPopulation);

        cities = readCities("D:\\个人\\cities.txt");
        Map<String, Optional<String>> stateToLongestCityName = cities.collect(groupingBy(City::getState,
                mapping(City::getName, maxBy(Comparator.comparing(String::length)))));
        System.out.println("stateToLongestCityName: " + stateToLongestCityName);

        locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<String>> countryToLanguage = locales.collect(groupingBy(Locale::getDisplayCountry,
                mapping(Locale::getDisplayLanguage, toSet())));
        System.out.println("countryToLanguage: " + countryToLanguage);

        cities = readCities("D:\\个人\\cities.txt");
        Map<String, IntSummaryStatistics> stateToCityPopulationSummary = cities.collect(groupingBy(City::getState,
                summarizingInt(City::getPopulation)));
        System.out.println(stateToCityPopulationSummary.get("a"));

        cities = readCities("D:\\个人\\cities.txt");
        Map<String, String> stateToCityName = cities.collect(groupingBy(City::getState,
                reducing("", City::getName, (s, t) -> s.length() == 0 ? t : s + "," + t)));
        System.out.println("stateToCityName: " + stateToCityName);

        cities = readCities("D:\\个人\\cities.txt");
        stateToCityName = cities.collect(groupingBy(City::getState, mapping(City::getName, joining(", "))));
        System.out.println("stateToCityName: " + stateToCityName);
    }

    public static Stream<City> readCities(String fileName) throws IOException {
        return Files.lines(Paths.get(fileName)).map(v -> v.split(", "))
                .map(a -> new City(a[0], a[1], Integer.parseInt(a[2])));
    }
}

运行结果:
在这里插入图片描述

12、约简操作

reduce方法是一种用于从流中计算某个值的通用机制。Optional<Integer> sum = values.stream().reduce((x, y) -> x + y); reduce方法会计算v0+v1+v2+…

13、基本类型流

流库中具有专门的类型IntStream、LongStream和DoubleStream,用来直接存储基本类型值,如果想要存储shor、char、byte和boolean,可以使用IntStream,而对于float,可以使用DoubleStream。

为了创建IntStream,需要调用IntStream.of和Arrays.stream方法:
IntStream stream = IntStream.of(1,2,3,4);
stream = Arrays.stream(values, from, to);

当你有一个对象流时,可以用mapToInt、mapToLong和mapToDoouble将其转换为基本类型流。
Stream<String words = ... ;
IntStream lengths = words.mapToInt(String::length);

通常,基本类型流上的方法与对象流上的方法类似。下面是最主要的差异:

  • toArray方法会返回基本类型的数组。
  • 产生可选结果的方法会返回一个OptionalInt、OptionalLong或OptionalDouble。这些类与Optional类类似,但是具有getAsInt、getAsLong和getAsDouble方法,而不是get方法。
  • 具有返回总和、平均值、最大值和最小值的sum、average、max和min方法。对象流没有定义这些方法。
  • summaryStatistics方法会产生一个类型为IntSummaryStatistics、LongSummaryStatistics或DoubleSummaryStatistics的对象,它们可以同时报告流的总和、平均值、最大值和最小值。

示例代码:

package com.java02.day01.streams;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-24 13:16
 */
public class PrimitiveTypeStreams {
    public static void show(String title, IntStream stream){
        final int SIZE = 10;
        int[] firstElements = stream.limit(SIZE + 1).toArray();
        for (int i = 0; i < firstElements.length; i++){
            if (i > 0){
                System.out.print(", ");
            }
            if (i < SIZE){
                System.out.print(firstElements[i]);
            }else {
                System.out.print("...");
            }
        }
        System.out.println();
    }

    public static void main(String[] args) throws IOException {
        IntStream is1 = IntStream.generate(() -> (int) (Math.random() * 100));
        show("is1", is1);
        //92, 67, 94, 77, 35, 19, 30, 63, 38, 48, ...
        IntStream is2 = IntStream.range(5, 10);
        show("is2", is2);
        //5, 6, 7, 8, 9
        IntStream is3 = IntStream.rangeClosed(5, 10);
        show("is3", is3);
        //5, 6, 7, 8, 9, 10

        Path path = Paths.get("D:\\个人\\demo.txt");
        String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);

        Stream<String> words = Stream.of(contents.split("\\PL+"));
        IntStream is4 = words.mapToInt(String::length);
        show("is4", is4);
        //5, 8, 2, 3, 5, 3, 4, 5, 5, 10, ...
        String sentence = "\uD835\uDD46 is the set of octonions";
        System.out.println(sentence);
        //𝕆 is the set of octonions

        IntStream codes = sentence.codePoints();
        sentence = codes.mapToObj(c -> String.format("%X ", c)).collect(Collectors.joining());
        System.out.println(sentence);
        //1D546 20 69 73 20 74 68 65 20 73 65 74 20 6F 66 20 6F 63 74 6F 6E 69 6F 6E 73

        Stream<Integer> integers = IntStream.range(1, 100).boxed();
        IntStream is5 = integers.mapToInt(Integer::intValue);
        System.out.println("is5" + is5);
        //is5java.util.stream.ReferencePipeline$4@42d80b78
    }
}

14、并行流

流使得并行处理块操作变得很容易。这个过程几乎是自动的,但是需要遵循一些规则。首先,必须有一个并行流。可以用Collection.parallelStream()方法从任何集合中获取一个并行流:Stream<String> parallelWords = words.parallelStream();
而且,parallel方法可以将任意的顺序流转换为并行流。Stream<String> parallelWords = Stream.of(wordArray).parallel();

为了让并行流正常工作,需要满足大量的条件:

  • 数据应该在内存中。必须等到数据到达是非常低效的。
  • 流应该可以被搞笑地分为若干个子部分。由数组或平衡二叉树支撑的流都可以工作得很好,但是Stream.iterate返回的结果不行。
  • 流操作的工作量应该具有较大的规模。如果总工作负载并不是很大,那么搭建并行计算时所付出的代价就没有什么意义。
  • 流操作不应该被阻塞。

示例代码:

package com.java02.day01.parallel;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

/**
 * @description:
 * @author: ju
 * @date: 2020-06-24 15:10
 */
public class ParallelStreams {
    public static void main(String[] args) throws IOException {
        String contents = new String(Files.readAllBytes(Paths.get("D:\\个人\\demo.txt")), StandardCharsets.UTF_8);
        List<String> wordsList = Arrays.asList(contents.split("\\PL+"));

        int[] shortWords = new int[10];
        wordsList.parallelStream().forEach(s -> {
            if (s.length() < 10){
                shortWords[s.length()] ++;
            }
        });
        System.out.println(Arrays.toString(shortWords));
        //[0, 0, 1, 3, 1, 6, 1, 0, 1, 0]

        Arrays.fill(shortWords, 0);
        wordsList.parallelStream().forEach(s -> {
            if (s.length() < 10){
                shortWords[s.length()] ++;
            }
        });
        System.out.println(Arrays.toString(shortWords));
        //[0, 0, 1, 3, 1, 6, 1, 0, 1, 0]

        Map<Integer, Long> shortWordsCount = wordsList.parallelStream().
                filter(s -> s.length() < 10).collect(groupingBy(String::length, counting()));
        System.out.println(shortWordsCount);
        //{2=1, 3=3, 4=1, 5=6, 6=1, 8=1}

        ConcurrentMap<Integer, List<String>> result = wordsList.parallelStream().
                collect(Collectors.groupingByConcurrent(String::length));
        System.out.println(result.get(5));
        //[Marry, every, happy, Happy, happy, happy]

        result = wordsList.parallelStream().
                collect(Collectors.groupingByConcurrent(String::length));
        System.out.println(result.get(5));
        //[Marry, Happy, happy, every, happy, happy]

        ConcurrentMap<Integer, Long> wordsCounts = wordsList.parallelStream().
                collect(Collectors.groupingByConcurrent(String::length, counting()));
        System.out.println(wordsCounts);
        //{2=1, 3=3, 4=1, 5=6, 6=1, 8=1, 10=1}
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值