jdk8 新特性学习总结

本文最后更新于1 分钟前,文中所描述的信息可能已发生改变。

jdk8中加入了很多新特性主要学习最常用的三点:

  1. 函数式接口、
  2. Lambda表达式、
  3. Optional、
  4. Stream流、

函数式接口:

概念: 函数式接口就是只包含一个抽象方法的接口。

在jdk8中,引入了PredicateFunctionConsumerSupplier等接口,这些接口都是函数式接口,因为他们只包含一个抽象方法。

在jdk8中,定义一个函数式接口都会带有@FunctionalInterface注解,表示这是一个函数式接口。 常用的函数式接口以及其使用场景如下:

常用的函数式接口:

  • Predicate(断言): 接受一个参数,返回布尔值结果。
java
Predicate<Integer> predicate = (num) -> num > 0;
  • Function(函数): 接受一个参数,返回一个结果。
java
Function<Integer, String> function = (num) -> "Number is: " + num;
  • Consumer(消费者): 接受一个参数,不返回结果,常用于处理数据。
java
Consumer<String> consumer = (str) -> System.out.println(str);
  • Supplier: 一般用于需要延时加载或获取某个数据时使用。 示例代码:
java
Supplier<Double> randomSupplier = () -> Math.random();
double randomValue = randomSupplier.get();
java
Supplier<Connection> connectionSupplier = () -> DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
Connection connection = connectionSupplier.get();

Lambda表达式:

jdk8的函数式接口

我觉得函数式接口主要是为了更好的实现lambda下的函数式编程。可以将一些功能很好的与lambda表达式更好的结合。

实例代码: 先声明一个函数式接口 OrderService, 包含一个generateOrder方法

java
@FunctionalInterface
public interface OrderService<K> {
    String generateOrder( K orderId);
}

普通代码写法:

java
OrderService IntegerCode = new OrderService<Integer>() {
    @Override
    public String generateOrder(Integer orderId) {
        return orderId + "_code";
    }
};

Lambda方式写法:

java
OrderService<Integer> intOrderCode = orderId -> orderId + "_code";

可以发现通过lambda表达式的方式,更优雅的书写上面的代码.更符合函数式编程的写法。

Stream流:

1.创建流:

集合:集合对象.stream() 数组:Arrays.stream( 数组) 双列集合:转换成单列集合后再创建

java
Map<String,Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.put("3",3);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

2.操作流:

filter 过滤

java
Map<String,Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.put("3",3);
map.entrySet().stream().filter(x -> x.getValue() > 1)

map

可以将流中的对象进行计算或转换。

java
Map<String,Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.put("3",3);
map.entrySet().stream()
        .filter(x -> x.getValue() > 1)
        .map(x -> x.getKey())  //获取过滤后的key值

distinct

去重,依赖的是Object的equals 方法来判断是否是相同的对象。 需要重写equals方法。

sorted

可以对流元素排序

java
Map<String,Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.put("3",3);
map.entrySet().stream()
        .filter(x -> x.getValue() > 1)
        .map(x -> x.getKey())
        .sorted(String::compareTo)

limit

可以设置流的最大长度,超出的部分将抛弃。

flatMap

map 只能将一个对象转换成另一个对象来作为流中的元素。flatMap则可以吧一个对象转换成多个对象作为流中的元素。

java
authors.stream()
        .flatMap(a -> a.getBooks().stream())
        .map(b -> b.getName())
        .distinct()
        .forEach(System.out::println);

flatmap需要保证最后返回的类型为 stream即可

3.终结操作:

foreach

对流中的元素进行遍历操作

count

获取流中元素的个数

collect

将流转换成集合转换成List 集合: .collect(Collectors.toList()); 转换成Set 集合: .collect(Collectors.toMap(k->k, v->v+"_value")); 需要传入两个 function分别定义keyvalue的取值方式

4. 查找与匹配:

匹配

anyMatch

判断是否有符合匹配的元素.anyMatch(s -> s.equals("a")) ? tmp.stream().collect(Collectors.toMap(s -> s, s -> s)) : null;

allMatch

判断是否都满足匹配条件

noneMatch

是否全部不符合条件

查找

findAny

查找任意一个匹配的元素

findFirst

查找第一个匹配的元素

reduce归并

对流中的元素按照既定的规则进行计算,得出一个结果 (缩减操作)其中的操作类似于对集合进行的累加操作

java
Integer[] arrs = {1, 2, 3, 4, 5};
int sum = 0;
for (Integer i : arrs) {
    sum = sum + i;
}
System.out.println(sum);

使用流进行累加操作

java
Arrays.asList(arrs).stream()
        .reduce(0, (a, b) -> a + b);

通过reduce计算最小值

java
Arrays.asList(arrs).stream()
        .reduce(Integer.MIN_VALUE, (res,current) -> res > current ? res : current);

还有一个一个参数的类型的方式:

java
Arrays.asList(arrs).stream()
        .reduce((a,b) -> a > b ? a : b);

第三种方式:

Optional

为了避免代码中总是进行空判断,或者出现空指针异常而出现。创建Optional 对象通常在创建方法时可以直接返回optional的对象创建方式:

java
Apple apple = new Apple();
Optional<Apple> opApple = Optional.ofNullable(apple);
消费:backservice.getUser().ifPresent(commonResult -> {
    System.out.println(commonResult);
});

获取其中的对象:

java
CommonResult result = backservice.getUser()
        .orElseGet(() -> new CommonResult(200, "empty", null));

过滤:

java
backservice.getUser().filter(r -> r.getCode() == 200)
        .ifPresent(r -> System.out.println(r.getData()));

判断:

java
if (backservice.getUser().isPresent()){
    System.out.println(backservice.getUser().orElseGet(() -> new CommonResult(200, "empty", null)).getData());
}

map转换:

java
backservice.getUser()
        .map(r -> r.getData())
        .ifPresent(r -> System.out.println(r));

函数式接口说明:概念:只有一个抽象方法的接口称作函数式接口。JDK的函数式接口都添加了 @FunctionalInterface 注解进行了注释。常用的函数式接口:在java/util 包中Consumer 消费接口Function 进行函数计算的接口Predicate 判断类型的接口Supplier 生产类型的接口拼接默认方法

java
andbackservice.getUser().filter(
        ((Predicate<CommonResult>) commonResult -> false).and(r -> r.getCode() == 200)
);

ornegate类似于与或非,理解即可

方法引用:

一个函数式的语法糖,可以进一步简洁lambda的写法。规则是如果方法体中只调用了一个方法,或者是构造方法的话,可以使用。规则1 :引用类的静态方法类名::静态方法

java
String[] strs = {"1", "2", "3", "4", "5"};
Arrays.stream(strs).map(str -> Integer.parseInt(str)).collect(Collectors.toList());
| |
 v
Arrays.stream(strs).map(Integer::parseInt).collect(Collectors.toList());

规则2:引用对象实例中的方法对象名::方法

java
List<String> randoms = Arrays.stream(strs).map(Integer::parseInt).map(this::generate).collect(Collectors.toList());

规则3:构造器引用

java
对象名::new Arrays.stream(strs).map(StringBuilder::new).map(t->t.append("_kol")).map(StringBuilder::toString).collect(Collectors.toList());

高级用法

书写中的优化注意:

java
Integer[] ints = {1, 2, 3, 4, 5};
Arrays.stream(ints)
        .map(i -> i + 10)
        .filter(i -> i > 13)
        .collect(Collectors.toList());

当存在上述的书写方式时,Integer 元素会经过多次的拆箱和装箱,当元素的个数达到一定的量的时候会严重影响流的效率。

java
List<Integer> ss = Arrays.stream(ints)
        .mapToInt(i -> i + 10)
        .filter(i -> i > 13)
        .boxed().collect(Collectors.toList());

可以在开始直接转换为int 类型,防止多次拆装箱,最后通过boxed 装箱为大类。

并行流:

开启并行流关键字parallel()

java
Stream<Integer> is = Stream.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50);
Integer total = is.parallel().reduce(0, (a, b) -> a + b);
System.out.println(total);

peek

通过peek可以进行调试

java
Integer total = is.parallel()
        .peek(i -> System.out.println("thread" + Thread.currentThread().getName() + ": " + i))
        .reduce(0, (a, b) -> a + b);
System.out.println(total);

parallelStream()可以直接获取并行流

maven settings.xml详细配置说明
建立springcloud项目