JDK 1.8新特性 日常总结

1、用JDK1.8 Stream中对List进行去重 

list = list.stream().distinct().collect(Collectors.toList());
List names = Arrays.asList("A",)

2、接口的默认方法

Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法

3、Lambda 表达式

传入一个List对象以及一个比较器来按指定顺序排列

Collections.sort(names, (a, b) -> b.compareTo(a));

4、Stream 接口

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 arrStream = Arrays.stream(arr);

    stream.forEach(s->System.out.println(s));  //使用完之后不能再使用,需要重新生成  才能再次使用
    // 2、集合   直接使用集合获取流
    List list = Arrays.asList("ab", "cd", "ef");
    Stream colStream = list.stream();
    // 3、值   直接使用静态方法,获取指定值的顺序排序流
    Stream stream = Stream.of("ab", "cd", "ef");

常用方法

forEach() 使用该方法迭代流中的每个数据

forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。

sorted() 使用该方法排序数据

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());

filter():使用该方法过滤

list.stream().filter((User user) -> user.getAge() > 50).forEach(user -> System.out.println(user));

limit():使用该方法截断

// 从第三个开始截断,只输出前三个

list.stream().limit(3).forEach(user -> System.out.println(user));

skip():与limit互斥,使用该方法跳过元素

// 跳过前三个元素,从第四个开始输出
list.stream().skip(3).forEach(user -> System.out.println(user));

stream流中的分页操作

一个skip和一个limit,skip代表着要跳过结果集中的前几个数据,limit也就是取结果集中的几个数据

stream.skip(2).limit(2).forEach(s -> System.out.println(s));

 

distinct():使用该方法去重

注意:如果数据类型是泛型,必须重写对应泛型的hashCode()和equals()方法

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));


max,min,sum,avg,count 

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():接收一个方法作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象

下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。

List collect = list.stream().map(s -> s.toUpperCase()).collect(toList());

stringCollection
    .stream()
    .map(String::toUpperCase)

末端的操作:

  • forEach 1 - 对流中的每个元素执行一些操作。
  • toArray 1 2 - 将流中的元素倾倒入一个数组。
  • reduce 1 2 3 - 通过一个二进制操作将流中的元素合并到一起。
  • collect 1 2 - 将流中的元素倾倒入某些容器,例如一个Collection或Map.
  • min 1 - 根据一个比较器找到流中元素的最小值。
  • max 1 -根据一个比较器找到流中元素的最大值。
  • count 1 - 计算流中元素的数量。
  • anyMatch 1 - 判断流中是否至少有一个元素匹配断言。这是一个短路的操作。
  • allMatch 1 - 判断流中是否每一个元素都匹配断言。这是一个短路的操作。
  • noneMatch 1 - 判断流中是否没有一个元素匹配断言。这是一个短路的操作。
  • findFirst 1 - 查找流中的第一个元素。这是一个短路的操作。
  • findAny 1 - 查找流中的任意元素,可能对某些流要比findFirst代价低。这是一个短路的操作。

 

 

具体其他方式调用举例说明

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

 

 

你可能感兴趣的:(JAVA技术)