java 8新特性--函数式编程

  最近实习过程中发现业务代码的编写多用Stream流,Optional类等等,发现这是Java 8中的新特性,对于集合类的操作非常便捷,于是抽空学习了一下Java 8 中的新特性。

Java8

  • 修改原因:

  抽象级别不够,面对大型数据集合操作,处理复杂,并行低效。

  • 变化:
    • 集合类API的增加;
    • Java 8中的另一个变化是引入了默认方法和接口的静态方法,它改变了人们认识类库的方式,接口中的方法也可以包含代码体了。

 

 

lambda表达式

  lambda表达式将行为像数据一样进行传递。使用操作符->,左边为参数(有时可以显式地声明参数类型),右边为执行的操作。

 

 

函数式接口

  1. 定义

  函数式接口本质上就是一个接口,里面只有一个抽象方法,用作 Lambda 表达式的类型。Java8中新增了java.util.function接口,函数式接口广泛用在支持lambda表达式的API中。这些接口有一个抽象方法,会被lambda表达式的定义所覆盖。

  • 如果在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的的定义来要求该接口。
  • 如果一个接口只有一个抽象方法,不管有多少个默认方法,有没有@FunctionalInterface注解,都是函数式接口。

 

  1. java.util.function中核心函数式接口

接口

参数

返回值

主要方法

Predicate<T>

T

boolean

boolean test(T t)

Consumer<T>

T

void

void accept(T t)

Function<T,R>

T

R

R apply(T t)

Supplier<T>

None

T

T get()

 

  1. 引用/实现函数式接口的方法
  • lambda表达式
  • 方法引用

  Java 方法引用Java 8随着Lambda表达式引入的新特性。其使用条件是:Lambda表达式的主体仅包含一个表达式,且Lambda表达式只调用了一个已经存在的方法;被引用的方法的参数列表和返回值与Lambda表达式的输入输出一致

    • 类名::静态方法名,例如Math::abs
    • 引用名(对象名)::实例方法名,例如this::equals
    • 类名::实例方法名,例如String::concat
  • 构造方法引用实现对应的实例
    • 类名::new

 

类库

 1 public interface Iterable<T> {
 2 
 3     Iterator<T> iterator();
 4 
 5     default void forEach(Consumer<? super T> action) {
 6         Objects.requireNonNull(action);
 7         for (T t : this) {
 8             action.accept(t);
 9         }
10     }
11     ...
12 }

 

  1. 默认方法

  Java8对接口进行了增强,接口中也可以有具体的方法实现了,不过必须要在方法之前加上修饰符default称为default method即默认方法。

  • default 关键字只能在接口中使用(以及用在 switch 语句的 default 分支),不能用在抽象类中。
  • 和抽象方法的区别:抽象方法,接口的子类需要实现;默认方法,接口的子类不需要实现,可以直接使用。
  • 方法不能够重写(覆盖) Object 中的方法,却可以重载Object 中的方法。eg:toString、equals、 hashCode 不能在接口中被覆盖,却可以被重载。
  • 多重继承下的三定律:
    • 类胜于接口。如果在继承链中有方法体或抽象的方法声明,那么就可以忽略接口中定义的方法。
    • 子类胜于父类。如果一个接口继承了另一个接口,且两个接口都定义了一个默认方法,那么子类中定义的方法胜出。
    • 没有规则三。如果上面两条规则不适用,子类要么需要实现该方法,要么将该方法声明为抽象方法
  1. 静态方法

  在接口中的方法签名前加上了 static 关键字。

 

  1. Optional类

  Optional 类(java.util.Optional) 是一个容器类,是为核心类库新设计的一个数据类型,用来替换 null 值。其API中的常用方法有:

  • Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
  • isPresent():判断是否包含值
  • get():返回该对象,有可能返回 null
  • orElse(T t):如果调用对象包含值,返回该值,否则返回t
  • orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值。 Supplier接口就一个get方法,无入参,出参要和Optional的对象同类型

 

 

Stream流

  Stream流和 java.io 包下的 InputStream 和 OutputStream 其实没有关系,他是Java8中新增的部分,极大的便捷了对于集合的遍历操作。集合主要是数据,而流主要是计算。

  使用stream流的优势在于它仅暴露一个Stream接口,很好地封装了内部的数据结构,用户在实际操作中无论如何使用都不会影响内部的List或Set。

 

创建流

  • 数组:Arrays.stream()或者Stream.of();
  • 集合Collection:.stream()方

 

stream流的中间操作

  • filter()

  从流中过滤出我们需要的数据流

 1 //找出数字开头的字符串
 2 List<String> beginningWithNumbers = new ArrayList<>(); 
 3 for(String value : asList("a", "1abc", "abc1")) {
 4     if (isDigit(value.charAt(0))) { 
 5         beginningWithNumbers.add(value);
 6     } 
 7 }
 8 
 9 //转化为如下,过滤后值为TRUE的元素保留,转化为list
10 List<String> beginningWithNumbers 
11 = Stream.of("a", "1abc", "abc1")
12     .filter(value -> isDigit(value.charAt(0))) 
13     .collect(toList());

 

  • map()

  映射,通过函数操作把一个流中的元素转化成新的流中的元素

  参数/返回值:接收的是一个 Function类型的参数(Java 8 新增的一个函数式接口,接受一个输入参数 T,返回一个结果 R,Function 接口是只包含一个参数的普通函数接口

  • flatMap()

  假如你的集合流中包含子集合,那么使用flatMap可以返回该子集合的集合流,也就是说返回集合中元素铺展开形成的流。

  flatMap/map区别:好比说现在有两个班的学生,每个班10人,map()返回值为两个班的集合,而flatmap()返回值为20个学生的集合。

 

  • distinct()

  去重,返回无重复元素的结果。

 

  • min()/max()

  求最值,只需要传递一个Comparator的comparing()方法即可,就可以进行比较,从而获取最大和最小值。

1 //求这组数中最大值
2 Integer maxNumber = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
3                     .max(Comparator.comparing(Integer::valueOf))
4                     .get();

 

 
  • reduce()

  reduce() 方法的主要作用是把 Stream 中的元素组合起来,从一组值生成一个值,它有两种用法:

    • Optional<T> reduce(BinaryOperator<T> accumulator)

    没有初始值,只有一个参数,就是运算规则,此时返回 Optional。运算规则可以是 Lambda 表达式(比如 (a, b) -> a + b),也可以是类名::方法名(比如 Integer::sum)。

    • T reduce(T identity, BinaryOperator<T> accumulator)

    有初始值,有运算规则,两个参数,此时返回的类型和起始值类型一致。

 

转换流

  • collect()

 

 

 

Reference

[1]Richard Warburton, 王群锋. Java 8函数式编程. 人民邮电出版社, 2015.

[2]Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft. Java 8实战.

posted @ 2021-06-30 10:57  每天前进一点点  阅读(475)  评论(0)    收藏  举报