Lambda
什么是Lambda
在编程语言中,Lambda指是一种运算符,被用于指定匿名函数或者是闭包。
为什么要使用Lambda
- 1.在Java中,我们无法将一个函数作为参数传递给方法,也无法声明返回一个函数
- 2.在JavaScript中,函数参数是一个函数,返回值是另一个函数的情况非常常见,JavaScript是一门典型的函数式语言
Lambda作用
传递行为,不仅仅是值
@FunctionalInterface介绍
在一个类上声明了@FunctionalInterface类的接口,称之为函数式接口,从概念上来看,一个函数式接口只有一个抽象方法,函数式接口实例可以通过lambda,方法引用或者是构造方法来创建,
特点:
1、唯一的抽象方法,有且仅有一个
2、可用于lamba类型的使用方式
3、不能被覆盖之后,再声明为抽象方法,则不算抽象方法。例如接口实现了Object中的方法。
4、加上标注,则会触发JavaCompiler的检查。对于符合函数接口的接口,加不加都无关紧要,但是加上则会提供一层编译检查的保障。如果不符合,则会报错。
关于函数式接口:
1、如果一个接口只有一个抽象方法,那么该接口就是函数式接口
2、如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口来要求自己
3、如果一个接口只有一个抽象方法,但是接口并没有声明FunctionalInterface注解,编译器也会对于满足函数式接口规范的接口当做函数式接口来看待。
java.util.function.Function<T,R>
接收一个参数,并生成一个结果,T:方法参数,R:方法结果返回值类型1
2
3
4
5//谁使用该function,那么就是谁调用toUpperCase()方法
//实例1
Function<String,String> function = String.toUpperCase;
//实例2,排序:倒序
Collections.sort(list,Comparator.reverseOrder());
高阶函数
如果一个函数接收一个函数作为参数,返回值为一个函数,那么该函数叫高阶函数
java.util.function.Function 方法介绍
方法compose
返回一个组合函数,首先将before函数应用于其输入,然后将此函数应用于结果。 如果任一函数的评估引发异常,则将其转发给组合函数的调用者。
andThen
返回一个组合函数,首先将此函数应用于其输入,然后将after函数应用于结果。 如果任一函数的评估引发异常,则将其转发给组合函数的调用者。
方法 identity
返回一个总是返回其输入参数的函数。
1 | System.out.println(compose(2,value -> value * 3,value -> value * value)) // 先执行f2,在执行f1 输出:12 |
java.util.function.BiFunction<T,U,R> 介绍
表示接受两个参数并产生结果的函数。
参数类型
- T - 函数的第一个参数的类型
- U - 函数的第二个参数的类型
- R - 函数结果的类型
1
2
3
4
5
6
7
int compute(int a, int b, BiFunction<Integer,Integer,Integer> bf) {
return bf.apply(a,b);
}
System.out.println(compute(1, 2, (v1,v2) -> v1 + v2)); // 3
System.out.println(compute(1, 2, (v1,v2) -> v1 - v2)); // -1
andThen()
返回一个组合函数,首先将该函数应用于其输入,然后将after函数应用于结果。 如果任一函数的评估引发异常,则将其转发给组合函数的调用者。
1 | System.out.println(2,3,(v1,v2) -> v1 + v2 ,v -> v * v); // 25 |
java.util.function.Consumer
表示一个动作,接收一个唯一的值,并不返回任何值,但是有个副作用:在方法里面可能会修改参数值(顾名思义:消费者)
java.util.function.Predicate
表示一个参数的谓词或者是判断(布尔值函数)。
这是一个functional interface,只有一个方法是test(Object)
test()方法
根据给定的参数上评估这个Predicate是true还是false。
1 | Predicate<String> predicate = p -> p.length > 5; |
and()
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。 当评估组合谓词时,如果此谓词为false ,则不执行other谓词。
在评估任一谓词期间抛出的任何异常被中继到调用者; 如果此断言的评价抛出一个异常, other断言不会被评估。
1 |
|
negate()
返回表示此谓词的逻辑否定的谓词 逻辑取反
1 | List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); |
or()
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或。 当评估组合谓词时,如果此谓词为true ,则不执行other谓词。
在评估任一谓词期间抛出的任何异常被中继到调用者; 如果此断言的评价抛出一个异常, other断言不会被评估。
static Predicate isEqual(Object targetRef)
返回一个Predicate,如果两个参数按照相等谓词 Objects.equals(Object, Object) 。
参数类型
T - Predicate的参数类型参数
targetRef - 用于比较相等的对象引用,可能是 null结果
根据 Objects.equals(Object, Object)测试两个参数是否相等的 谓词
1 | isEqual(isEqual("test").test("test")) |
public interface Supplier
代表结果供应商。
没有要求每次调用供应商时都会返回新的或不同的结果。
这是一个functional interface的功能方法是get() 。
T get()
获得结果
1 | Supplier<String> supplier = () -> "hello word"; |
BinaryOperator extends BiFunction<T,T,T>
表示对同一类型的两个操作数的操作,产生与操作数相同类型的结果。 对于操作数和结果都是相同类型的情况,这是BiFunction的具化 。
这是一个functional interface的功能方法是BiFunction.apply(Object, Object) 。
static BinaryOperator minBy(Comparator<? super T> comparator)
根据Comparator返回BinaryOperator,返回两个参数中最小的那个参数
static BinaryOperator maxBy(Comparator<? super T> comparator)
和minBy相反
java.util.Optional
为了解决NPE NullPointerException 空指针异常
可能包含或不包含非空值的容器对象。 如果一个值存在, isPresent()将返回true并使用get()获取返回值。
提供依赖于存在或不存在包含值的其他方法,例如orElse() (如果值不存在则返回默认值)和ifPresent() (如果值存在则执行代码块)。
这是一个value-based一个类; 使用身份敏感的操作(包括引用相等(的==上的实例),标识哈希码,或同步) Optional可具有不可预测的结果,应当避免。
什么叫基于值的一个类:value-based一个类
https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html
有些类,例如java.util.Optional和 java.time.LocalDateTime,都是基于值value-based的一个类,它们满足以下几个特点:
- 是final和immutable(不可变)(尽管可能包含对可变对象的引用);
- 具有的实现equals, hashCode和toString其中从实例的状态仅计算,而不是来自它的身份或任何其他物体或变量的状态;
- 不使用身份敏感的操作,例如==实例之间的引用相等(),实例的身份哈希代码,或实例的内部锁定上的同步;
- 被认为是完全相同的equals(),而不是基于参考相等(==);
- 没有可访问的构造函数,而是通过工厂方法实例化,这些方法不会对返回的实例的身份做出承诺;
- 当相等时,它们是可自由替换的,这意味着根据任何计算或方法调用交换任何两个实例x并且y相等,equals()应该不会产生行为的可见变化。
如果程序试图将两个引用区分为基于值的类的相等值,无论是直接通过引用相等还是间接通过引发同步,身份哈希,序列化或任何其他身份敏感机制,程序可能会产生不可预测的结果。对基于值的类的实例使用此类身份敏感操作可能具有不可预测的影响,应该避免。
1 | Optional<String> optional = Optional.of("hello"); |
方法引用:method reference.
方法引用实际上是lambda的语法糖
1 | List<String> list = Arrays.asList("a","b","c"); |
我们可以将方法引用看做是「函数指针」function pointer
方法引用共分为四类
- 1、类名::方法
- 2、引用(对象)::方法
- 3、类名::对象实例方法
- 4、构造方法引用:类名::new
Stream
- Collection 提供了一个新的Stream方法
- 流不存储值的,通过管道的方式获取值
- 本质是函数式的,对流的操作结果会生成一个结果,不过并不会修改底层的数据源,集合可以作为流的底层数据源
- 延迟查找,很多流操作(过滤,映射,排序)都可以延迟实现
方法
A[] toArray(IntFunction<A[]> generator)
1 | Stream<String> stream = Stream.of("hello", "world", "helloWorld"); |
R collect(Supplier supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
参数类型
R - 结果的类型
参数
- supplier - 创建新结果容器的函数。 对于并行执行,可以多次调用此函数,并且每次都必须返回一个新的值。最终要返回的结果
- accumulator -一个 associative(相关联) , non-interfering(不冲突,不妨碍) , stateless功能用于将一个额外的元件到结果
- combiner -一个 associative , non-interfering , stateless功能用于组合两个值,它必须与蓄能器功能兼容
对此流的元素执行可变的汇集(reduction)或者是精简的操作。一个可变的汇集值指的是被汇集的值是的是可变的结果容器,比如说是一个ArrayList。并且通过更新结果的状态而不是通过替换结果来合并元素。 这产生的结果相当于:1
2
3
4R result = supplier.get();
for (T element : this stream)
accumulator.accept(result, element);
return result;
像reduce(Object, BinaryOperator)一样 , collect操作可以并行化,而不需要额外的同步。这是一个终止操作
JDK中有许多现有的类,其签名非常适合用作参考的方法引用到collect() 。 例如,以下将会将字符串累加到一个ArrayList :List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
以下将使用一串字符串并将它们连接成一个字符串:
1 | String concat = stringStream.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); |
代码示例1
Stream<String> stream = Stream.of("hello", "world", "helloWorld");