我有一个学生名单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调用的。

09-28 06:17