Consumer类

今天学习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)是什么意思呢?

另附上
在这里插入图片描述

新人写博客,如有错误,烦请指出,感激不尽

是的,您提到的问题是因为在Java中使用方法引用时,实际上会生成一个代理来实现函数式接口。因此,通过`Thread.currentThread().getStackTrace()[1].getMethodName()`获取的是代理的方法名,而不是原始的方法名。 要解决这个问题,您可以在A中添加一个成员变量,用于记录当前执行的方法名。在每个方法内部,将方法名赋值给该成员变量。这样,在Consumer中就可以通过访问A的成员变量来获取当前执行的方法名。 以下是修改后的示例代码: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; class ClassA { private String currentMethodName; public void setCurrentMethodName(String methodName) { this.currentMethodName = methodName; } public void method1(Map<String, Object> map) { setCurrentMethodName("method1"); // 方法1的逻辑代码... } public void method2(Map<String, Object> map) { setCurrentMethodName("method2"); // 方法2的逻辑代码... } public void method3(Map<String, Object> map) { setCurrentMethodName("method3"); // 方法3的逻辑代码... } public void method4(Map<String, Object> map) { setCurrentMethodName("method4"); // 方法4的逻辑代码... } } public class Main { public static void main(String[] args) { List<Consumer<Map<String, Object>>> methods = new ArrayList<>(); ClassA rule = new ClassA(); methods.add(rule::method1); methods.add(rule::method2); methods.add(rule::method3); methods.add(rule::method4); Map<String, Object> map = new HashMap<>(); // 异常处理 methods.forEach(method -> { try { method.accept(map); // 获取当前执行方法的方法名 ClassA classA = new ClassA(); String methodName = classA.currentMethodName; System.out.println("当前执行的方法名为:" + methodName); } catch (Exception e) { e.printStackTrace(); } }); } } ``` 在上述代码中,我们在ClassA中添加了一个currentMethodName成员变量,并为其提供了一个setter方法。在每个方法内部,都调用了setCurrentMethodName方法来设置当前执行的方法名。然后,在Consumer中,我们通过创建一个新的ClassA对象并访问其currentMethodName成员变量来获取当前执行的方法名。 请注意,这种方法仅在A中的方法直接被调用时有效,如果A的方法通过其他方式间接调用,例如通过父或接口引用调用,则无法正确获取方法名。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值