list = list.stream().distinct().collect(Collectors.toList());
List names = Arrays.asList("A",)
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法
传入一个List对象以及一个比较器来按指定顺序排列
Collections.sort(names, (a, b) -> b.compareTo(a));
java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。
Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身
虽然大部分情况下stream是容器调用Collection.stream()方法得到的,但stream和collections有以下不同:
1.无存储:stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
2.为函数式编程而生:对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
3.惰式执行:stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
4.可消费性:stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
一、获取stream
// 1、数组 使用的Arrays类的stream方法
String[] arr = new String[]{"ab", "cd", "ef"};
Stream
stream.forEach(s->System.out.println(s)); //使用完之后不能再使用,需要重新生成 才能再次使用
// 2、集合 直接使用集合获取流
List
Stream
// 3、值 直接使用静态方法,获取指定值的顺序排序流
Stream
forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。
list.stream().sorted(Comparator.comparing(User::getAge)).forEach(user -> System.out.println(user));
多个元素排序:coreRspList = coreRspList.stream().sorted( Comparator.comparing(LoanOutStatisticsRspDto::getLoanOutAmount).reversed() .thenComparing(Comparator.comparing(LoanOutStatisticsRspDto::getToLoanOutAmount).reversed()) ).collect(Collectors.toList());
list.stream().filter((User user) -> user.getAge() > 50).forEach(user -> System.out.println(user));
// 从第三个开始截断,只输出前三个
list.stream().limit(3).forEach(user -> System.out.println(user));
// 跳过前三个元素,从第四个开始输出
list.stream().skip(3).forEach(user -> System.out.println(user));
一个skip和一个limit,skip代表着要跳过结果集中的前几个数据,limit也就是取结果集中的几个数据
stream.skip(2).limit(2).forEach(s -> System.out.println(s));
list.stream().distinct(Comparator.comparing(User::getAge)).forEach(user -> System.out.println(user));
复杂场景:去重+按照年龄大于40以后从小到大+只取前二
list.stream().distinct().filter(user -> user.getAge() > 40).sorted(
Comparator.comparing(User::getAge)).limit(2).forEach(user -> System.out
.println(user));
IntSummaryStatistics num = list.stream().mapToInt(u -> u.getAge())
.summaryStatistics();
System.out.println("总共人数:" + num.getCount());
System.out.println("平均年龄:" + num.getAverage());
System.out.println("最大年龄:" + num.getMax());
System.out.println("最小年龄:" + num.getMin());
System.out.println("年龄之和:" + num.getSum());
中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象
下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。
List
stringCollection
.stream()
.map(String::toUpperCase)
末端的操作:
Match 匹配
boolean anyStartsWithA = stringCollection.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA = stringCollection.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
boolean noneStartsWithZ = stringCollection.stream().noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
Count 计数
计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。
long startsWithB = stringCollection.stream().filter((s) -> s.startsWith("b")).count();
System.out.println(startsWithB); // 3
Reduce 规约
这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的:
Optional reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
并行Streams
前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
下面的例子展示了是如何通过并行Stream来提升性能:
首先我们创建一个没有重复元素的大表:
int max = 1000000;
List values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
然后我们计算一下排序这个Stream要耗时多久,
串行排序 // 串行耗时: 899 ms
long t0 = System.nanoTime();
long count = values.stream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));
并行排序:// 并行排序耗时: 472 ms
long t0 = System.nanoTime();
long count = values.parallelStream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));
唯一需要做的改动就是将stream()改为parallelStream()
Clock 时钟
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant); // legacy java.util.Date