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}
}
}