我现在想实现这种的效果

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

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

@FunctionalInterface
public interface FunctionOperation 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 Object setProperty1(Object object, FunctionOperation 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 Object setProperty1(Object object, FunctionOperation a,FunctionOperation 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但是好像没有效果。就卡住了我也不知道该怎么处理了

回答

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

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

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

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

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

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

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

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

BiConsumer consumerName = (u, str) -> u.setName(str);

BiConsumer 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方法直接做写入的,题主之前用的JavaBeans的PropertyDescriptor,如果要按照PropertyDescriptor的方式写一个lambda表达式,那就是另一种写法

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

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

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

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

public interface CustomBiConsumer {
/**
* 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 consumerName = (u, value) ->
new PropertyDescriptor("name", u.getClass()).getWriteMethod().invoke(u, value);
CustomBiConsumer consumerAge = (u, value) ->
new PropertyDescriptor("age", u.getClass()).getWriteMethod().invoke(u, value);

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

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

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

一个输入,一个输出的FunctionalInterface,在jdk里有么?

有!那就是Function

所以我们就可以把consumerName和consumerName提取出一个公共的方法,这个公共方法的抽象就是一个Function>

它的实现写为

Function> consumerFunction =
propName -> (u, value) -> new PropertyDescriptor(propName, u.getClass())
.getWriteMethod()
.invoke(u, value);
所以我们之前的consumerName和consumerName就可以写做
Function> consumerFunction =
propName -> (u, value) -> new PropertyDescriptor(propName, u.getClass())
.getWriteMethod()
.invoke(u, value);
CustomBiConsumer consumerName = consumerFunction.apply("name");
CustomBiConsumer consumerAge = consumerFunction.apply("age");

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