13. Java新特性

Java 8其他新特性

1. Lambda表达式

1.1 介绍
Lambda是一个匿名函数,使用它可以写出更简洁、更灵活的代码。Java中lambda表达式的本质是作为函数式接口的实例。 在函数式编程语言中,lambda表达式的类型时函数,而在Java中,lambda表达式是对象,它们必须依附于一类特别的对象类型:函数式接口。

Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("r1");
    }
};
r1.run();

Runnable r2 = () -> {
	System.out.println("r2");
	};
r2.run();

1.2 格式

  • ->:lambda操作符,又称箭头操作符
  • ->左边:lambda形参列表,存放接口中抽象方法的形参列表
  • ->右边:lambda体,重写抽象方法的方法体

1.3 使用

  • lambda表达式可以有多个形参,可以有多条执行语句,可以有返回值
  • lambda形参列表的数据类型可以省略,称为类型推断
  • lambda形参列表只需要一个参数时,参数的小括号可以省略
  • lambda体只有一条语句时,return和大括号都可以省略

2. 函数式接口

2.1 定义
如果一个接口中,只声明了一个抽象方法,称为函数式接口。可以通过lambda表达式来创建函数式接口的对象。可以在一个接口上使用@FunctionalInterface注解,从而检验该接口是否是一个函数式接口。Java 8在java.util.function包下定义了丰富的函数式接口。

2.2 Java内置函数式接口
Java内置四大核心函数式接口:

函数式接口参数类型返回类型用途
Consumer< T >消费型接口Tvoid对类型为T的对象应用操作,void accept(T t)
Supplier< T >供给型接口T返回类型为T的对象,T get()
Function< T,R >函数型接口TR对类型为T的对象应用操作,并返回结果:R apply(T t)
Predicate< T >断定型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t)

3. 方法引用与构造器引用

3.1 方法引用

  • 方法引用可以看做是lambda表达式深层次的表达,可以认为是lambda表达式的一个语法糖
  • 使用情境:当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用
  • 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致(第3种格式不满足该要求)
  • 格式:使用操作符“::”将类(对象)与方法名分隔开

对象 :: 非静态方法
类名/对象 :: 静态方法
类名 :: 非静态方法(实现接口的抽象方法的返回值类型与方法引用的方法一致,参数列表比方法引用的参数多一个,调用方法引用的对象作为第一个参数,左边的类写该对象所在的类)

3.2 构造器引用

  • 要求:函数式接口的抽象方法的形参列表和构造器的形参列表一致,抽象方法的返回值类型即为构造器所属类的类型
  • 格式:类名 :: new

3.3 数组引用

  • 要求:把数组看作一个特殊的类,其他操作与构造器引用相同
  • 格式:String[] :: new

4. Stream API

4.1 介绍
4.1.1 概述
Stream API(java.util.stream)把真正的函数式编程风格引入到Java中,提供了一种高效易用的处理数据的方式。使用Stream API对集合数据进行操作,就类似于使用SQL进行数据库查询。

4.1.2 特性

  • Stream自己不会存储元素
  • Stream不会改变源对象,操作会返回一个持有结果的新Stream
  • Stream操作时延迟执行的,需要结果时才会执行

4.1.3 步骤

  • 创建Stream对象:通过一个数据源(集合、数组),获取一个流
  • 中间操作:一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果,之后不会再被使用

4.2 创建Stream对象
4.2.1 通过集合创建
Java8中的Collection接口被扩展,提供了两个获取流的方法:

  • default Stream<E> stream():返回一个顺序流
  • default Stream<E> parallelStream():返回一个并行流

4.2.2 通过数组创建
Java8中的Arrays的静态方法stream()可以获取数组流:

  • static <T> Stream<T> stream(T[] array):返回一个流

4.2.3 通过Stream的of()方法创建
Stream的静态方法of()通过显示值创建一个流,可以接收任意数量的参数:

  • public static<T> Stream<T> of(T… values):返回一个流

4.2.4 创建无限流
使用静态方法Stream.iterate()和Stream.generate()可以创建无限流:

  • public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f):迭代
  • public static<T> Stream<T> generate(Supplier<T> s):生成

4.3 中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何处理。在终止操作时一次性全部处理,称为“惰性求值”。

4.3.1 筛选与切片

  • filter(Predicate p):接受lambda,从流中排除某些元素
  • distinct():筛选,通过流所生成元素hashCode()和euqals()去除重复元素
  • limit(long maxSize):截断流,使其元素不超过给定数量
  • skip(long n):跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("AAA");
arrayList.add("ABB");
arrayList.add("BBA");
Stream<String> stream = arrayList.stream();
stream.filter(s -> s.substring(0, 1).equals("A")).forEach(System.out::println);

4.3.2 映射

  • map(Function f):接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

这两个方法类似于list.add(list)和list.addAll(list)的区别

4.3.3 排序

  • sorted():产生一个新流,其中按自然顺序排序
  • sorted(Comparator com):产生一个新流,其中按比较器顺序排序
List<Integer> list = Arrays.asList(12, 45, 34, 75, 3, 26);
list.stream().sorted().forEach(System.out::println);

4.4 终止操作
终止操作会从流水线生成结果,其结果可以是任何不是流的值。流进行了终止操作后,不能再次使用。

4.4.1 匹配与查找

  • allMatch(Predicate p):检查是否匹配所有元素
  • anyMatch(Predicate p):检查是否至少匹配一个元素
  • noneMatch(Predicate p):检查是否没有匹配所有元素
  • findFirst():返回第一个元素
  • findAny():返回当前流的任意元素
  • count():返回流中元素总数
  • max(Comparator c):返回流中最大值
  • min(Comparator c):返回流中最小值
  • forEach(Consumer c):内部迭代(iterator称为外部迭代)

4.4.2 归约

  • reduce(T iden, BinaryOperator b):将流中元素反复结合起来,得到一个值,返回T
  • reduce(BinaryOperator b):将流中元素反复结合起来,得到一个值,返回Optional<T>
List<Integer> list = Arrays.asList(12, 45, 34, 75, 3, 26);
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);

4.4.3 收集

  • collect(Collector c):将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

Collectors类中提供了很多静态方法,可以方便创建常见的收集器实例:

  • toList():把流中元素收集到List
  • toSet():把流中元素收集到Set
  • toCollection():把流中元素收集到创建的集合
List<Integer> list = Arrays.asList(12, 45, 34, 75, 3, 26);
List<Integer> collect = list.stream().filter(i -> i > 20).collect(Collectors.toList());
System.out.println(collect);

5. Optional类

5.1 介绍
为了解决空指针异常,Google公司引入了Optional类。Optional<T>类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,代表这个值不存在。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

5.2 方法
5.2.1 创建Optional类对象

  • Optional.of(T t):创建一个Optional实例,t必须非空
  • Optional.empty():创建一个空的Optional实例
  • Optional.ofNullable(T t):t可以为null

5.2.2 判断Optional容器中是否包含对象

  • boolean isPresent():判断是否包含对象
  • void ifPresent(Consumer<? super T> consumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它

5.2.3 获取Optional容器的对象

  • T get():如果调用对象包含值,返回该值,否则抛异常
  • T orElse(T other):如果有值则将其返回,否则返回指定的other对象
  • T orElseGet(Supplier<? extends T> other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象
  • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常
String str = "hello";
Optional<String> optional1 = Optional.of(str);
String s = optional1.get();
System.out.println(s);

str = null;
Optional<String> optional2 = Optional.ofNullable(str);
String s1 = optional2.orElse("hi");
System.out.println(s1);

Java 9/10/11新特性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值