xinrong2019 / xinrong2019.github.io

My Blog
https://xinrong2019.github.io
1 stars 1 forks source link

20190623 Java8新特性 #76

Open xinrong2019 opened 5 years ago

xinrong2019 commented 5 years ago

主要是语法

1、Lambda表达式

2、函数式接口

3、方法引用和构造器引用

4、Stream API

5、Optional类

学习的思维方式:

1、大处着眼,小处着手

2、逆向思维、反证法

3、透过问题看本质

4、小不忍则乱大谋

5、识时务者为俊杰

6、学思结合

Java8新特性

jjs.exe

xinrong2019 commented 5 years ago

关于函数式接口

只有一个方法的接口,称为函数式接口。

可以通过Lambda表达式来创建函数接口的对象。

Lambda表达式的实例是一个函数式接口的实例。

只要一个对象是函数式接口的实例,就可以用Lambda表达式来表示。

Java8中,Lambda表达式是对象,不是函数,必须依赖函数式接口。

FunctionalInterface注解可以用来检验函数式接口,类似于Overide注解的作用。

xinrong2019 commented 5 years ago

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

Consumer<T>

参数类型:T

返回类型:void

用途:对类型为T的对象操作,包含方法:void accept(T t)

Supplier<T>

参数类型:无

返回类型:T

用途:返回类型为T的对象,包含方法:T get()

Function<T,R>

参数类型:T

返回类型:R

用途:对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)

Predicate<T>

参数类型:T

返回类型:boolean

用途:确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t)

xinrong2019 commented 5 years ago

方法引用

方法引用是一种特殊的Lamba表达式

也是函数式接口的一个实例,通过方法的名字来指向一个方法。

要求:

实例接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法参数列表和返回值类型保持一致

如下三种使用情况:

1、对象::实例方法名

2、类::静态方法名

3、类::实例方法名

情况1:对象::实例方法

Consumer中的void accept(T t) PrintStream中的void println(T t)

情况2:类::静态方法

Comparator中的int compare(T t1,T t2) Integer中的int compare(T t1,T t2)

Function中的R apply(T t) Math中的Long round(Double d)

情况3:类::实例方法

Comparator中的int compare(T t1,T t2) String中的int t1.compareTo(t2)

BiPredicate中的boolean test(T t1,T t2) String中的boolean t1.equals(t2)

Function中的R apply(T t) Employee中的String getName()

xinrong2019 commented 5 years ago

构造器引用

Supplier中的T get() Employee的无参构造器:Employee

Supplier sup2 = Employee::new;

Function中的R apply(T t)

BiFuntion中的R apply(T t,U u)

构造器引用和方法引用类似,只要有匹配的函数式接口的形参列表和构造器的形参列表一样,就可以使用。

抽象方法的返回值类型即为构造器所属的类的类型。

数组引用

Function<Integer,String[]> func = String[] :: new;

xinrong2019 commented 5 years ago

Stream API

Stream是有关计算的,关注的时运算,面向CPU。

Stream操作的三个步骤:

1、创建Stream

2、中间操作

3、终止操作

终止操作时,执行中间操作,并产生结果,之后不会再被使用

xinrong2019 commented 5 years ago

1、创建Stream

集合,通过集合的stream()方法

数组,通过Arrays.stream(数组)

通过Stream.of()创建Stream

创建无限流,造数据(了解)

迭代

Stream.iterate(0,t ->t + 2).limit(10).forEach(System.out::println);

生成

Stream.generate(Math::random).limit(10).forEach(System.out::println);

xinrong2019 commented 5 years ago

2、中间操作

1、筛选和切片

distinct()通过流所生成元素的hashCode()和equals()去除重复元素

2、映射

操作流中每个元素

将流中的每个值换成另一个流,然后将所有流连接成一个流,类似于集合的addAll方法。

3、排序

产生一个新流,按自然顺序排序

产生一个新流,其中按比较器排序

xinrong2019 commented 5 years ago

3、终止操作

从流的流水线上生成结果。

1、匹配与查找

检查是否匹配所有元素,集合为空,返回true(有点坑,注意使用)

检查是否至少匹配一个元素

检查是否没有匹配所有元素

返回optinal类型

返回第一个元素

返回当前流中的任意元素

返回long类型

传入一个消费者,数据必须时从参数带来的

生产者:自己生产数据

2、规约

可以将流中元素反复结合起来,得到一个值,返回T。

T是初始值,BinaryOperator是反复操作

可以将流中元素反复结合起来,得到一个值。返回Optional

1、计算1-10的自然数的和

2、计算公司所有员工工资的总和。

3、收集

将流收集为List、Set、Map

collect(Collectors.toList())

toList

toSet

toCollection

counting

summingInt

对流中元素的整数属性求和

averagingInt

计算流中元素Integer属性的平均值

summarizingInt

收集流中Integer属性的统计值。如:平均值

xinrong2019 commented 5 years ago

Optional类

Optional类是一个容器类,可以保存类型T的值,代表这个值存在。

可以理解为对null的一个包装,是面向对象的设计。类似与包装类对基本数据类型的包装。

不够优雅的代码:

if(boy != null){
    Girl girl = boy.getGirl();
    if(girl != null){
        return girl.getName();
    }
}

优雅的写法

Optional<Boy> boyOptional = Optional.ofNullable(boy);

Boy boy1 = boyOptional.orElse(new Boy(new Girl("张三")));

Girl girl = boy1.getGirl();

Optional<Girl> girlOptional = Optional.ofNullable(girl);

Girl girl1 = girlOptional.orElse(new Girl("李思思"));

把ifelse代码转换为可读性更好的方法