请问方法引用之后如何赋值

发布于 2022-09-12 03:13:48 字数 3068 浏览 10 评论 0

我现在想实现这种的效果

Beanutils.setProperty1(user, User::getName);

我参照网上的例子定义了一个接口类

@FunctionalInterface
public interface FunctionOperation<T> extends Serializable {
    //这里只接收无参方法
    Object get(T source);

    //这个方法返回的SerializedLambda是重点
    default SerializedLambda getSerializedLambda() throws Exception {
        //writeReplace改了好像会报异常
        Method write = this.getClass().getDeclaredMethod("writeReplace");
        write.setAccessible(true);
       return (SerializedLambda) write.invoke(this);

    }



    default String getImplClass() {
        try {
            return getSerializedLambda().getImplClass();
        } catch (Exception e) {
            return null;
        }
    }

    default String getImplMethodName() {
        try {
            return getSerializedLambda().getImplMethodName();
        } catch (Exception e) {
            return null;
        }
    }

定义了实现方法

    public static <T>  Object setProperty1(Object object, FunctionOperation<T> a)  {
        try{


        }catch (Exception e){
            e.printStackTrace();
        }
        return  object;
    }

我在这里边如何操作,其他服务调用这个方法的时候

Beanutils.setProperty1(user, User::getName);

当我这么调用的时候,我希望在上边那个实现方法里给这个name赋值比如说 “aaa”,但是我使用反射的方法好像没有成功,想问一下一般都是如何处理
<!-------------------------------------------------------->
修改:
我没有表述清楚我的想法,我现在有两个方法,这两个方法我希望实现的功能是一样的

 public static Object setProperty(Object object,String a,String b)  {
        Class target =   object.getClass();
        try{
            PropertyDescriptor descriptor = new PropertyDescriptor(a,target);
            Method method= descriptor.getWriteMethod();    //
            method.invoke(object,"1");
            PropertyDescriptor descriptor2 = new PropertyDescriptor(b,target);
            Method method2= descriptor.getWriteMethod();    //
            method2.invoke(object,"1");
        }catch (Exception e){
            e.printStackTrace();
        }
        return  object;
    }

    public static <T>  Object setProperty1(Object object, FunctionOperation<T> a,FunctionOperation<T> b)  {
        try{


        }catch (Exception e){
            e.printStackTrace();
        }
        return  object;
    }

我在controller调用了这两个方法

public static void main(String[] args) {
        User user = new User();
        user.setAge("1111");
        System.out.println(user.toString());
        try {

            Beanutils.setProperty(user,"name","age");

            //想采用这种方式
             Beanutils.setProperty1(user, User::getName,User::getAge);


        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(user);
    }

一种格式是
Beanutils.setProperty(user,"name","age")
传递字符串这种,我希望可以传递User::getName这种,也就是下边这样
Beanutils.setProperty1(user, User::getName,User::getAge);
我尝试在setProperty1方法里也是用setProperty方法里的那种invoke但是好像没有效果。就卡住了我也不知道该怎么处理了

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

傻比既视感 2022-09-19 03:13:48

看来后续的补充才算明白setProperty1只是为了设置默认的属性值,其实题主你之前写这个User::getName,User::getAge对我影响太大了,我老想到get操作去,你这个不是赋值,所以应该是set操作嘛

这个方法引用,其实就是lambda表达式嘛,方法引用只是快捷写法,那lambda表达式其实就是把方法做了抽象

而一个方法是需要关心输入输出的,那lambda表达式也需要关注输入和输出。

题主想要setProperty1方法和setProperty效果一样,所以setProperty1方法中的参数传入的lambda表达式应该也要做到给属性赋值的操作。

那这个lambda表达式的输入是什么?

setProperty1方法中能给到的是参数有object对象以及默认的输入值"1",所以传入的lambda表达式的输入就应该是object"1",返回可以为空,因为这个lambda表达式里我只对某个属性做设置操作就可以了

那我们jdk中提供了有没有根据两个参数做操作,但是返回voidFunctionalInterface呢?当然有的,那就是BiComsumer

image.png

之前提到lambda表达式就是一个方法的抽象,所以我们可以看到BiComsumer这个方法的抽象要求有两个参数,然后返回void,因此我们就可以这样来设计setProperty1方法中后两个参数的传入

BiConsumer<User, String> consumerName = (u, str) -> u.setName(str);
BiConsumer<User, String> consumerAge = (u, str) -> u.setAge(str);

当然setProperty1方法就应该改为

public static Object setProperty1(Object object, 
                                  BiConsumer consumer1, 
                                  BiConsumer consumer2)  {
     try{
         consumer1.accept(object, "1");
         consumer2.accept(object, "1");
     }catch (Exception e){
         e.printStackTrace();
     }
      return  object;
}

最终直接调用为

Beanutils.setProperty1(user, consumerName, consumerAge);

当然现在这种写法是按照set方法直接做写入的,题主之前用的JavaBeansPropertyDescriptor,如果要按照PropertyDescriptor的方式写一个lambda表达式,那就是另一种写法

但是大体思路结构是类似的

BiConsumer<User, String> consumerName = (u, value) -> 
         new PropertyDescriptor("name", u.getClass()).getWriteMethod().invoke(u, value);
BiConsumer<User, String> consumerAge = (u, value) -> 
         new PropertyDescriptor("age", u.getClass()).getWriteMethod().invoke(u, value);

看起来一样,不过你可以去试试,编译会报错的,在new PropertyDescriptor上,因为new PropertyDescriptor显示的抛出了异常,而我们的BiConsumeraccept方法没有throws 异常,因此要改的话,就不能在用BiComusmer了,需要自己写一个

比如我们写一个CustomBiComusmer,和BiComusmer类似,只是accept方法抛出异常即可

public interface CustomBiConsumer<T, U> {

    /**
     * Performs this operation on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u) throws Exception;
}

然后把BiComsumer换成我们的CustomBiConsumer就可以啦,setProperty1方法中的参数也记得改哦

CustomBiConsumer<User, String> consumerName = (u, value) ->
       new PropertyDescriptor("name", u.getClass()).getWriteMethod().invoke(u, value);
CustomBiConsumer<User, String> consumerAge = (u, value) -> 
       new PropertyDescriptor("age", u.getClass()).getWriteMethod().invoke(u, value);

这样就可以了么?其实还可以再精炼一点,我们平常写方法都会公共方法提到一起,那lambda表达式作为方法的抽象,当然也可以做一次整合

因为我们发现consumerNameconsumerAge非常接近,他们的差别只是参数传入的"name""age"的差距,其他都一样

因此此时如果再把这种我们要处理的情况看成是一个方法,那根据我们之前说的,此时方法的输入应该是一个属性名,只有一个输入,输出是什么?那当然是我们要的CustomBiConsumer

一个输入,一个输出的FunctionalInterface,在jdk里有么?
有!那就是Function
image.png

所以我们就可以把consumerNameconsumerName提取出一个公共的方法,这个公共方法的抽象就是一个Function<String, CustomBiConsumer<User, String>>

它的实现写为

Function<String, CustomBiConsumer<User, String>> consumerFunction = 
       propName -> (u, value) -> new PropertyDescriptor(propName, u.getClass())
                                    .getWriteMethod()
                                    .invoke(u, value);

所以我们之前的consumerNameconsumerName就可以写做

Function<String, CustomBiConsumer<User, String>> consumerFunction = 
       propName -> (u, value) -> new PropertyDescriptor(propName, u.getClass())
                                     .getWriteMethod()
                                     .invoke(u, value);
CustomBiConsumer<User, String> consumerName = consumerFunction.apply("name");
CustomBiConsumer<User, String> consumerAge = consumerFunction.apply("age");

以上就是简单的想法把,感觉题主可能对于lambda表达式还不是很透彻,如果你能把后几个用例看明白,尤其是consumerFunction看懂,估计也就没什么问题啦,仅供参考哈,债见ヾ( ̄▽ ̄)Bye~Bye~

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文