Java之Stream流


流在java的官方文档中被定义为视图。通过流去完成什么样的任务,而不是如何去实现它。通俗一点来讲它相对于集合就是表达了做什么,而不是怎么做。
流和集合的差异
1.流并不储存数据,数据还是储存在底层的集合中。
2.流的操作并不能修改数据,它只是在原本的流中产生新的流。
3.流的操作是惰性的,只要不使用终结方法提交操作我们就可以一直无限流。

流有
stream() //流 将任何集合转换为一个流
parallelStream() //并行流、顺序流

流的创建

Stream<String> words = Stream.of(contents.split("\\PL+")); //将数组转换成为流
Stream<String> silence = 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));

 

filter、map 和 flatMap 方法

//过滤产生新的流
List<String> wordList = ...;
Stram<String> longWords = wordList.stream().filter(w -> w.length() > 12);

//用map转换成新的流
Stream<String> lowercaseWords = words.stram().map(String :: toLowerCase);
Stream<String> firsLetters = words.stram().map(s -> s.substring(0, 1));

//用flatMap 将所有当前流中所有元素连接到一起
Stream<String> flatResult = words.stream().flatMap(w -> ... );

抽取子流和连接流

//获取一个限制大小的流
Stream<Double> randows = Stream.generate(Math :: random).limit(100);
//丢弃前n个元素
Stream<String> words = Stream.of(contents.split("\\PL+")).skip(1);
//连接两个元素的流
Stream<String> combined = Sream.concat( ... , ...);

其他的流转换

//剔除重复元素的流
Stream<String> uniqueWords = Stream.of("a", "a", "b", "c").distinct();
//对流进行排序
Stream<String> longesFirst = words.stram().sorted(Comparator.comparing(String :: length).reversed());
//peek 产生和原来的流相同,但是每次获取一个元素时都调用一次函数
Object[] powers = Stream.iterate(1.0, p -> p*2).peek(e -> System.out.println("Fetching" + e)).limit(20).toArray();

简单约简
约简是一种终结操作。

//获取最大值
Optional<String> largest = words.max(String :: compareToIgnoreCase);

Optional<T>类型
Optional<T>对象是一种包装器对象,要么包装了T类型的对象,要么没有包装任何对象。
如何使用Optional值

 

//没有任何匹配的时候返回空字符串
String result = optionalString.orElse("");
//计算默认值
String result = optionalString.orElseGet(() -> Locale.getDefault().getDisplayName());
//没有任何值时抛出异常
String result = optionalString.orElseThrow(IllegalStateException :: new);

//如果值存在将它添加进某个集中
optionalVlaue.ifPresent(v -> results.add(v));
//
optionalValue.ifPresent(results :: add);

ifPresent不会返回任何值,如果想处理函数结果过应该使用map
//added 可能存在三种值,true、false、空的Optional
Optional<Boolean> added = optionalValue.map(results :: add);

 

 

不适合使用OPtional值的方式
在Optional值为null使用get将会抛出NoSuchElementException对象。
所以不要直接使用get()方法,应先判断值是否存在。

if(optionalValue.isPresent())
optionalValue.get().someMethod();
//
if(vlaue != null)
value.someMethod();

创建Optional值

Optional.of(result)和Optional.empty()

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

ofNullable方法
ofNullable(obj)会在obj不为null 的情况返回Optional.of(obj),否则返回Optional.empty()。

用flatMap来构建Optional值的函数
flatMap就像是管道,在Optional<T>对象的方法f有产生另外的Optional<U>对象g时不能直接调用s.f().g()。
因为它们属于不同类型的Optional<T>。则是就可以用到flatMap。

Optional<U> result = s.f().flatMap(T :: g)

收集结果
当处理完流之后,想要获取里面的元素是。可以调用iterator方法或者forEach
stream.forEach(System.out :: println);
在并行流上,forEach方法会以任意顺序遍历。如果想按流中的顺序可以调用forEachOrdered方法。
更多的是转变成为一种数据结构。可以调用toArray。
收集到数组中
因为无法在运行时创建泛型数组,所以steam.toArray()会返回一个Object[]数组。
如果想正确创建指定类型数组。

String[] result = stream.toArray(String[] :: new);

收集到集合中

List<String> result = stream.collect(Collectors.toList());
//
Set<String> result = stream.collect(Collectors.toSet());
//如果想指定集合种类
TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet :: new));

连接流中所有字符串

String result = stream.collect(Collectors.joinjing());
//想加分割符
String result = stream.collect(Collectors.joinjing(","));
//如果不是字符串,得先转成字符串
String result = stream.map(Object :: toString).collect(Collectors.joining(","));

对流的结果约简为总和、平均值、最大值或最小值

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


收集到映射表中
假设有Stream<Person>

Map<Integer, String> idToName = people.collect(Collectors.toMap(Person :: getId, Person :: getName));
//第二值也可使用函数
Map<Integer, String> idToName = people.collect(Collectors.toMap(Person :: getId, Function.identity()));

如果有多个元素相同的键将会抛出IllegalStateExcpetion对象
这时可以使用第三个函数来处理冲突

Stream<Locale> locale = Stream.of(Locale.getAvailableLocales());
Map<String, String> languages = locales.collect(
    Collectors.toMap(
      Locale :: getDisplayLanguage,
      l -> l.getDisplayLanguage(l),
      (existingValue, newValue) -> existingValue
  )
);

群组和分区
groupingBy一种更方便的方法,它会见现有的集与新集合并。

Map<String, List<Locale>> countryToLocales = locales.collect(Collectors.groupingBy(Locale :: getCountry));
List<Local> swissLocales = countryToLocales.get("CH");

分类函数是断言函数,在这种情况下使用partitioningBy比使用groupingBy更高效

Map<Boolean, List<Locale>> englishAanOtherLocales = locales.collect(
Collectors.partitioningBy(l -> l.getLanguage().equals("en")));
List<Local> englishLocales =englishAndToLocales.get(true);

groupingByConcurrent方法使用并行流时可获得并行映射表与toConcurrentMap方法类似。

下游收集器

//groupingBy产生的映射表,它的每个值是列表,想获得集就得
Map<String, Set<Locale>>countryToLocaleSet = locales.collect(groupingBy(Locale :: getCountry, toSet()));
//counting收集元素个数
Map<String, Long> countryToLocalCounts = locales.collect(groupingBy(Locale :: getCountry, counting()));
//summing(Int|Long|Double) 接受引元,产生它们的和
Map<String, Integer> stateToCityPopulation = locales.collect(
  groupingBy(City :: getState, summingInt(City :: getPopulation)));
//maxBy、minBy获取最大、小值
Map<String, Optional<City>>stateToLargestCity = cities.collect(
  groupingBy(City :: getState, maxBy(Comparator.comping(City :: getPopulation))));
//mapping方法使用函数
Map<String, Optional<String>> stateToLargestCityName = cities.collect(
  groupingBy(City :: getState, mapping(City :: getName, maxBy(Comparator.comping(String :: length)))));
//mapping方法收集到集
Map<String, Set<String>> countryToLanguages = locales.collect(
  groupingBy(Locale :: getDisplayCountry, mapping(Locale :: getDisplayLanguage, toSet())));
//IntSummaryStatistics使用汇总(适用int、long、double)
Map<String, IntSummaryStatistics> stateToCityPopulationSummary = cities.collect(
  groupingBy(Ctiy :: getState, summarizing(Ctiy :: getPopulation)));

 

posted @ 2019-09-09 11:37  知识航海家布尔  阅读(501)  评论(0编辑  收藏  举报