函数式接口
有且只有一个抽象方法的接口被称为函数式接口,函数式接口适用于函数式编程的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象,一定要确保接口中有且只有一个抽象方法,这样Lambda才能顺利的进行推导。
@FunctionalInterface注解
该注解可用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法(equal和hashcode方法不算),否则将会报错。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。
- Function(函数型接口):主要针对的则是转换**(有入参,有返回,其中T是入参,R是返回)**这个场景。
- Consumer(消费性接口):主要针对的是消费(1..n 入参, 无返回)。
- Supplier(供给型接口):主要针对的是说**获取(无入参,有返回)**这个场景。
- Predicate(断言型接口):主要针对的是判断(有入参,有返回,凡是返回的类型固定为Boolean。可以说Function 是包含Predicate的 )。
Function
Function<Integer, String> function = r -> {
return String.valueOf(r);;
}
String fun(Integer r) {
return String.valueOf(r);
}
Java SE 8 引入了一个名为 java.util.function.Function
的函数式接口,它代表一个函数,接受一个参数并产生一个结果。包括以下4个主要的抽象方法:
- apply(T t):接收一个参数并产生一个结果。
- compose(before.apply(T t)):在apply 前执行其它操作
- andThen(after.apply(R r)):在apply 后执行其它操作
- identity():返回一个输入参数的identity 函数
您可以使用该接口定义一个函数,例如将一个字符串转换为大写:
Function<String, String> toUpperCase = string -> string.toUpperCase();
Consumer
Consumer<String> consumer = r -> {
System.out.println(r);
}
void fun(String r){
System.out.println(r)
}
Java SE 8 中引入了一个叫做java.util.function.Consumer
的函数式接口,它代表了一个接受一个输入参数而无返回结果的操作。它包括以下2个重要的抽象方法:
- accept(T t):接收一个参数,无返回值
- andThen(after.accept(T t)):如果这两个Consumer 实例都不是空的,则此方法会返回一个合成的Consumer ,它串行调用此Consumer实例的accept 方法,然后继续调用给定的Consumer实例的accept方法
您可以使用该接口定义接受一个字符串并将其打印到控制台的操作:
Consumer<String> consumer = r -> System.out.println(r);
consumer.accept("hello world");
Supplier
Supplier<Integer> supplier = () -> {
return 1;
}
Integer fun() {
return 1;
}
Java SE 8 中引入了一个名为 java.util.function.Supplier
的函数式接口,它表示结果的提供者。它会提供一个get() 方法,以便提供一个结果。
您可以使用此接口定义一个返回当前系统时间的方法:
Supplier<Long> supplier = () -> System.currentTimeMillis();
System.out.println(supplier.get());
Supplier是惰性的,只有执行了get()方法,才会执行代码块的内容。
Predicate
Predicate<String> predicate = s -> {
return s.equals("a");
}
boolean fun(String s) {
return s.equlas("a");
}
Java SE 8 中引入了一个叫做 java.util.function.Predicate
的函数式接口,它代表一个谓词(传入一个参数,返回一个布尔值)。它包括以下2个重要的抽象方法:
- test:传入一个参数,返回一个布尔值
- and/or/negate:将两个Predicate 连接起来
您可以使用它定义一个确定字符串长度是否大于0:
Predicate<String> predicate = (s) -> s.length() > 0;
System.out.println(predicate.test("foo"));
Lambda表达式
何为Lambda
Lambda 并不是一个什么的缩写,它是希腊第十一个字母 λ 的读音,同时它也是微积分函数中的一个概念,所表达的意思是一个函数入参和出参定义,在编程语言中其实是借用了数学中的 λ,并且多了一点含义,在编程语言中功能代表它具体功能的叫法是匿名函数(Anonymous Function)
匿名函数(英语:Anonymous Function)在计算机编程中是指一类无需定义标识符(函数名)的函数或子程序。
Lambda 在编程语言中往往是一个匿名函数,也就是说Lambda 是一个抽象概念,而编程语言提供了配套支持,比如在 Java 中其实为Lambda 进行配套的就是函数式接口,通过函数式接口生成匿名类和方法进行Lambda 式的处理。
Java Lambda表达式
句法
- 零参数:
() -> System.out.println("零参数 lambda");
- 一个参数:
p -> System.out.println("一个参数:" + p);
- 多个参数:
(p1 [,p2,p3,....pn]) -> System.out.println("多个参数:" + p1 + ", " + p2 + ... + pn);
上面的表达式有一定的限制。它们要么返回一个值要么执行一段方法,并且它们不能包含变量、赋值或语句,例如if or for 。为了进行更复杂的操作,可以使用带有花括号的代码块。如果 lambda 表达式需要返回一个值,那么代码块应该有一个return语句。
(parameter1, parameter2) -> { code block [return] }
方法引用
- 类 :: 静态方法
Function<String, Integer> function = r -> {
return Integer.valueOf(r);
};
Function<String, Integer> function = Integer::valueOf;
- 对象 :: 实例方法
List<String> list = Lists.newArrayList();
Consumer<String> consumer = r -> list.add(r);
Consumer<String> consumer = list::add;
- 构造器 :: new
Supplier<Object> supplier = () -> new Object();
Supplier<Object> supplier = Object::new;
Stream表达式
Stream,就是JDK8又依托于函数式编程特性为集合类库做的一个类库,它其实就是jdk提供的函数式接口的最佳实践。它能让我们通过lambda表达式更简明扼要的以流水线的方式去处理集合内的数据,可以很轻松的完成诸如:过滤、分组、收集、归约这类操作。
Stream的操作大致分为两类
- 中间型操作
- 终结型操作
中间型操作就是返回值依旧是Stream类型的方法。api如下:
终结型操作与中间型相反,返回值是非Stream类型的。api如下:
注意:Stream是惰性的,只有在执行终结型操作时,才会执行中间型操作代码。
Stream.of("1", "2", "3")
.peek(System.out::println) // 不会打印
.map(Integer::valueOf);
Stream.of("1", "2", "3")
.peek(System.out::println) // 会
.map(Integer::valueOf)
.count();