【Java】请问方法引用之后如何赋值
我现在想实现这种的效果
Beanutils.setProperty1(user, User::getName);
我参照网上的例子定义了一个接口类
@FunctionalInterfacepublic 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但是好像没有效果。就卡住了我也不知道该怎么处理了
回答
看来后续的补充才算明白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<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
方法直接做写入的,题主之前用的JavaBeans
的PropertyDescriptor
,如果要按照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
显示的抛出了异常,而我们的BiConsumer
的accept
方法没有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
表达式作为方法的抽象,当然也可以做一次整合
因为我们发现consumerName
和consumerAge
非常接近,他们的差别只是参数传入的"name"
和"age"
的差距,其他都一样
因此此时如果再把这种我们要处理的情况看成是一个方法,那根据我们之前说的,此时方法的输入应该是一个属性名,只有一个输入,输出是什么?那当然是我们要的CustomBiConsumer
一个输入,一个输出的FunctionalInterface
,在jdk
里有么?
有!那就是Function
所以我们就可以把consumerName
和consumerName
提取出一个公共的方法,这个公共方法的抽象就是一个Function<String, CustomBiConsumer<User, String>>
它的实现写为
Function<String, CustomBiConsumer<User, String>> consumerFunction = propName -> (u, value) -> new PropertyDescriptor(propName, u.getClass())
.getWriteMethod()
.invoke(u, value);
所以我们之前的consumerName
和consumerName
就可以写做
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~
以上是 【Java】请问方法引用之后如何赋值 的全部内容, 来源链接: utcz.com/a/88407.html