一、概述
面向对象思想关注用什么对象完成什么事情。而函数式编程思想就类似数学中的函数。它关注的是对数据进行了说明操作。(类似把具体的操作代码通过参数的形式传递进去)
1、代码简洁、接近自然语言;
2、越来越多的非关系型数据库应用,大数据量下处理集合十分高效方便;
3、易于并发编程;
二、Lambda表达式
jdk8的其中一个语法,函数式思想的一个重要体现,核心原则:可推导可省略
1、如果匿名内部类是一个结果,并且只有一个抽象方法需要实现,(例如起一个Thread)则可以修改为lambda表达式;
2、只关注参数和函数体,idea可以使用alt+回车可以帮助智能转换成lambda表达式
3、省略规则
参数类型可以省略
方法体中只有一句代码时大括号return和唯一一句代码的分号可以省略
方法只有一个参数时小括号可以省略
三、Stream流
对集合或数组进行操作,不会影响原数据(我们在流中可以处理很多数据,但是正常情况下是不会影响到原来集合中的元素的。
流代码分为三步:
1、创建流
2、中间操作
filter map distinct sorted limit skip flatmap
map()方法中的第一个泛型不能改(第一个类型就是对象的元素,已经是定义好的,不能修改不然会报错),但是第二个泛型是可以修改的(可以修改为想要的数据类型),简单理解为就是把流当中的元素转换为另外一种元素类型然后再放到流中。
mapToInt() 高级用法.....还有mapTOLong()等等,针对基本数据类型进行优化。
流中的distinct()是依赖Object中的equals方法来判断是否为相同对象的。所以使用distinct方法需要重写equals方法;
limit()用法(截取*个元素)
skip()用法(跳过第*个元素)
流中的sorted()是需要对象去实现是Comparable接口,不然会抛出ClassCastException异常。实现有两种方式,一种是在操作的对象中实现,第二种是通过匿名内部类的方式去实现。
flatMap()可以把一个对象转换为多个对象放到流中。
3、终结操作
流必须要要有终结操作,否则无法执行。流被终结以后无法再次使用。
forEach()对流中的元素进行遍历操作。
count()返回此流中元素的计数。
max() min() 获取流中的最值。
collect() 是将流中的元素转为一个集合。
anyMatch() 根据逻辑判断返回布尔值。
allMatch() 可以用来判断是否都符合逻辑判断条件,返回布尔值。
noneMatch() 可以用来判断是否都卢符合逻辑判断条件,返回布尔值。
findAny() 查找流中的任意一元素该方法无法保证获取的元素一定是流中的第一个元素。
ifPresent() 如果Optional对象不为null则继续往下执行。为null就不继续往下执行。
findFirst()获取流中的第一个元素。
reduce(),归并,即把sream中的元素组合起来计算出一个结果。传入一个参数,循环流中元素进行操作(可以对传入的参数进行比较等操作),并返回一个传入参数类型的数据。
reduce两个参数的重载形式内部的计算方式如下:
T result = identity;
for(T element : this stream){
result = accumlator.apply(result,element);
}
return result;
四、Optional
养成使用Optional的习惯可以写出更加优雅的代码来避免空指针异常。
实际开发过程中很多数据是通过数据库来获取的,Mybatis从3.5版本以后也支持Optional了。可以直接把dao方法的返回值类型定义为Optional类型,Mybatis会自己把数据封装为Optional对象返回。封装的过程也不需要我们自己去操作。
很多函数式编程相关的API都用了Optional。
Optional.ofNullable() 将对象封装为Optional对象。无论传入的参数是否为null都不会出现问题。(建议使用 )
Optional.of() 传入的参数必须不能为null。(不建议使用)
Optional.empty() 返回一个空的Optional对象。
Optional.ifPresent() 该方法会判断其内部封装的数据是否为空,不为空的时候才能执行具体的消费代码。
Optional.isPresent() 该方法会判断其内部封装的数据是否为空,为空返回false,不为空返回true.
Optional.filter() 在方法中进行逻辑判断,如果满足会返回Optional对象;不满足则返回null.
Optional.map() 将对象中的值转为Optional>对象.
如果想要安全的获取Optional对象中的值,不推荐使用get()方法。推荐使用以下几种方法。
Optional.orElseGet() 如果Optional中的值为null,可以自定义返回一个对象。
Optional.orElseThrow() 如果Optional中的值为null,可以手动抛出异常。
五、函数式接口
**JDK的函数式接口中都加上了@FunctionalInterface注解进行标识,无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。**
**JDK自带的常用函数式接口**
Comparator 消费接口
Function 计算转换接口
Predicate 判断接口
Supplier 生产型接口
**方法引用**
类名或对象名::方法名
写完Lambda表达式以后,发现方法体只有一行代码,并且这行代码调用了某个对象的成员方法,方法所有参数都按照顺序传入,这时候就可以引用对象的实例方法,方法调用时候使用Idea快捷键能够转换成方法引用即可。
六、高级玩法
map()方法中的第一个泛型不能改(第一个类型就是对象的元素,已经是定义好的,不能修改不然会报错),但是第二个泛型是可以修改的(可以修改为想要的数据类型),简单理解为就是把流当中的元素转换为另外一种元素类型然后再放到流中。
mapToInt() 高级用法.....还有mapTOLong()等等,针对基本数据类型进行优化。
七、并行流
**当流中有大量元素,可以使用并行流提高操作效率。其实并行流就是把任务分配给多个线程去完成。如果使用Stream的话,只需要修改一个方法的调用就可以使用并行流来提高效率**
Stream.parallel()方法
parallelStream() 直接获取并行流