今天学习mybatisPlus的时候看到了list.forEach(System.out::println())这个东西,百思不得其解,后续查看资料发现和Consument<T>类有关
观看底层源码
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
这个Consumer类就只有两个方法,其中有一个还是默认方法
先来看看accept这个方法,他的参数是一个泛型,默认不指定时为Object类
使用Lambda表达式,来使用这个接口
public class Test {
public static void speak(String name , Consumer<String> consumer) {
consumer.accept(name);
}
public static void main(String[] args) {
speak("张三",(String name) -> {
System.out.println(name);
});
}
}
那个lambda表达式的意思就是重写了接口里的方法,它返回了一个接口的子类对象回来(实现这个接口的类),调用speak方法就是需要一个String类型的参数和一个Consumer<T>类型的参数
还有一个默认的方法andThen,使用andThen方法,把两个Consumer接口连接到一起,再消费数据
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
例子
public class Test {
public static void speak(String name , Consumer<String> consumer1,Consumer<String> consumer2) {
//consumer1.accept(s);
//consumer2.accept(s);
//使用andThen方法,把两个Consumer接口连接到一起,在消费数据
consumer1.andThen(consumer2).accept(name);
}
public static void main(String[] args) {
speak("abc",(x) -> {
System.out.println(x.toUpperCase());
},(x) -> {
System.out.println(x.toLowerCase());
});
}
}
看完Consumer类之后,我们就要去看list.forEach()方法的底层源码了
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
forEach是一个默认方法,只有Iterable<T>这个接口的实现类可以调用,看看它的参数就是Consumer接口,而Consumer接口又是函数式接口,所以可以进行方法引用
例子:
这里的1是实例方法引用,2是静态方法引用。DemoInterface1是一个函数式接口,里面有一个抽象方法,对于函数式接口我觉得可以不用关心他的方法名,只需要关心他的返回值类型和参数列表就好了。
这里DemoInterface1 jiekou3 = p::plan1的意思就是把p对象的plan1方法给了DemoInterface1接口的抽象方法,注意这里的方法引用不是随便给的,需要保证接口所要求的返回值类型和参数列表与被引用的方法的返回值类型和参数列表保持一致。
回到刚刚的代码片段
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
forEach方法的参数是Consumer,而Consumer是一个函数式接口,所以我们可以使用方法引用形式去实现这个Consumer接口
现在再来看看list.forEach(System.out::println) 是不是就很好理解了
System.out 返回了一个PrintStream对象,使用了PrintStream的println方法,::(双冒号)代表了对这个实例的方法引用
我们就把Consumer接口给实现了,Consumer的accept方法就等于了System.out.println这个方法
看到这里你是否明白了list.forEach(System.out::println)是什么意思呢?
另附上
新人写博客,如有错误,烦请指出,感激不尽