我有一个学生名单List<Student>
我正在使用javassist-3.9.0.GA jar。
当我写list.stream().collect(Collectos.grouping(Student::getCode))
时
它给Caused by: java.io.IOException: invalid constant type: 18
异常。当我将上面的语句更改为list.stream().collect(Collectos.grouping(p->p.getCode()))
时,它可以工作。p->p.getCode()
和Student::getCode
的字节码操作不一样吗?
当使用相同的javassist时,以上两个语句如何工作不同?
概括:
我有一个像这样的类(class):
class Student{
private String code;
private String name;
public String getCode(){
return code;
}
public void setCode(){
this.code=code;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
}
List<Student> studentList=getStudentList();
现在,下面的语句是在javassist-3.9.0.GA jar上可以正常工作
Map<String,List<TripDetail>> tripMap=studentList.stream().collect(Collectors.groupingBy(p -> p.getCode()));
但是具有相同的Jar下面的语句给
invalid constant type: 18
异常Map<String,List<TripDetail>> tripMap=studentList.stream().collect(Collectors.groupingBy(Student::getCode));
因此,据我所知
p -> p.getCode()
和Student::getCode
都相同,因此要么都应该给出该异常,要么都应该正常工作。 最佳答案
根据答案here,Javassist 3.9不完全支持您正在使用的Java 8功能。如果可以,请升级Javassist。如果没有,您将受p -> p.getCode()
版本的困扰。
至于两种语法之间的区别,p -> p.getCode()
是一个lambda表达式,它创建一个新的匿名函数来调用其参数上的getCode()
。参数类型来自表达式实现的功能接口(interface)。
同时,Student::getCode
不会创建新函数,它只是一个lambda表达式,它引用了getCode
的现有Student
方法。
根本上的区别是p -> p.getCode()
不属于任何人,而Student::getCode
属于Student
。
我编译了一个简单的示例,以了解对方法调用有什么影响。对于p -> p.getCode()
版本,将生成以下字节码:
SourceFile: "LambdaExampleAnonymous.java"
BootstrapMethods:
0: #51 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#52 (Ljava/lang/Object;)Ljava/lang/Object;
#55 invokestatic example/LambdaExampleAnonymous.lambda$0:(Lexample/Student;)Ljava/lang/String;
#56 (Lexample/Student;)Ljava/lang/String;
使用
Student::getCode
版本,您将获得以下信息:SourceFile: "LambdaExampleReference.java"
BootstrapMethods:
0: #44 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#45 (Ljava/lang/Object;)Ljava/lang/Object;
#50 invokevirtual example/Student.getCode:()Ljava/lang/String;
#52 (Lexample/Student;)Ljava/lang/String;
您可以看到匿名lambda函数是使用
invokestatic
调用的,而引用的方法是使用invokevirtual
调用的。