概述
java8主要增加了函数式接口(@FunctionalInterface)、lambda表达式、流(stream)。
函数式接口
什么样的接口是函数式接口
1、被注解@FunctionalInterface修饰的,并且只有一个抽象方法的接口叫函数式接口。
2、没有被@FunctionalInterface注解修饰,但是也只有一个抽象方法的接口,也会被编译器认为是函数式接口
3、java8中规定,接口中可以有默认方法(defalut)修饰,和static方法。只要有一个抽象方法,不管这个接口中还有多少的默认方法和静态方法,改接口都是函数式接口。
例如1.8中的Function接口,有2个default方法和一个static方法以及一个抽象的apply方法,所以Function接口依然是一个函数式接口:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
4、如果一个函数式接口有多个抽象方法,但是除了自己定义的一个抽象方法外,其他的抽象方法都是父类的抽象方法,则这个接口也是函数式接口。
例如:
@FunctionalInterface
interface MyInterface1{
void apply();
String toString();
}
这里toString()父类object的方法,不会报错。如果在增加一个自定义的抽象接口,就会报错,不满足函数是借口定义。如:
lambda表达式与函数式接口的关系。
每一个函数式接口的实现都可以由lambda表达式来创建,所以说lambda表达式的本质是一个接口的实现类,是一个对象,并且定义了函数式接口中的唯一抽象方法的行为。
例如:
可以通过lambda表达式定义一个MyInterface1的实现类,通果控制台打印直到,实例a实现了MyInterface1接口。
lambda表达式的作用
1、可以将函数作为参数传递给方法,实现行为传递。以前java是值传递,现在可以传递行为(方法),这时一种更高层次的抽象。
例如:
aaa方法的func1参数是一个函数式接口类型,我们可以在调用的时候具体定义指定要执行的行为(排序、大小写转换、求和。。。),以前每一种行为都需要定义一个方法,现在只需要一个函数式接口参数,在调用的时候具体传递行为。这是对方法更高一级的抽象。
2、使代码更简洁,更容易理解。
lambda表达式的格式
lambda表达式的标准格式:
有三部分
一些参数
一个箭头
一段代码
格式:
(参数列表)->{一些重写方法的代码}
解释说明格式:
()接口中抽象方法的参数列表:没有参数空,有就写,多个用,分割
->传递的意思,把参数传递给方法体{}
{}重写接口的抽象方法的方法体
如果只有一个参数可以省略()
如果{}中只有一个表达式,可以省略{}和return(如果有返回值的话)
如下两者等价:
Function<String, String> func1 = x -> x + "2";
Function<String, String> func2 = (x) -> {return x + "2";};
java8中定义的常见的函数式接口
1、Comsumer 消费型接口
定义一种行为,接收一个类型为T的参数,没有返回值
@FunctionalInterface
public interface Consumer<T> {
//接收一个方法为T的参数,没有返回值
void accept(T t);
//先执行调用者的accept方法,消费一次t
//在返回一个持有Consumer<? super T> after的Consumer对象,然后调用accept方 法在消费一次t
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer<String> consumer = System.out::println;
consumer.accept("test");
Consumer<String> consumer = x -> System.out.println(x + "1");
consumer.andThen(x -> System.out.println(x + "2")).accept("aa");
//consumer 调用accept返回aa1
//after(就是x -> System.out.println(x + "2"))调用accept返回aa2
2、Supplier :供给型接口
定义一种行为,没有输入,返回一个T类型的返回值
@FunctionalInterface
public interface Supplier<T> {
//返回一个T类型的参数
T get();
}
Supplier<UUID> sp = UUID::randomUUID;
System.out.println(sp.get().toString());
3、Function<T,R>:函数型接口
给一个输入参数T,返回一个R类型的返回值
@FunctionalInterface
public interface Function<T, R> {
//输入t,返回R
R apply(T t);
//将before.apply(v)的返回值作为调用者apply方法的参数
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//将调用者apply的返回值,作为after的apply方法的参数
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
4、Predicate:断言型接口
定义一种断言行为,输入参数T,判断是否满足所定义的行为,返回布尔值。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Predicate<String> p = x -> x.length() > 5;
p.test("abcfrs");
5、BiFunction<T, U, R> :函数类型
定义一种行为,输入两个参数T,U;返回R类型的值
@FunctionalInterface
public interface BiFunction<T, U, R> {
//输入两个参数,返回R
R apply(T t, U u);
//先执行调用者的apply方法啊,返回值R在作为Function after的输入参数
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
思考:为什么没有beforce,因为BiFunction和Function返回者只有一个,andThen中的参数只能是Function类型,而beforce只需要一个参数,而输入参数有2个。
注意:这些函数式接口,只是定义一种抽象的行为,可以将这些接口作为方法的参数,具体调用的时候传递具体实现。也就是传递行为或者传递函数。