java 8,当使用相同的 javassist 时,Lambda 表达式的工作方式不同

Nis*_*hat 5 java javassist java-8 java-stream

我有一个学生名单,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()))时。

字节码manupulationp->p.getCode()Student::getCode不一样吗?

在使用相同的 javassist 时,上述两个语句的工作方式有何不同?

总结:我有一个类喜欢:

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;
   }
}
Run Code Online (Sandbox Code Playgroud)

List<Student> studentList=getStudentList();

现在下面的语句在 javassist-3.9.0.GA jar 上运行良好

Map<String,List<TripDetail>> tripMap=studentList.stream().collect(Collectors.groupingBy(p -> p.getCode()));
Run Code Online (Sandbox Code Playgroud)

但在下面的声明中使用相同的 Jar 给出了invalid constant type: 18例外

Map<String,List<TripDetail>> tripMap=studentList.stream().collect(Collectors.groupingBy(Student::getCode));
Run Code Online (Sandbox Code Playgroud)

所以据我所知p -> p.getCode()Student::getCode两者都是相同的,所以要么两者都应该给出例外,要么两者都应该工作。

Sam*_*Sam 2

根据此处的答案,Javassist 3.9 不完全支持您正在使用的 Java 8 功能。如果可以的话,升级 Javassist。如果没有,你就会被这个p -> p.getCode()版本困住。

两种语法之间的区别在于p -> p.getCode()lambda 表达式,它创建一个调用getCode()其参数的新匿名函数。参数类型来自表达式所实现的函数接口。

同时,Student::getCode并没有创建一个新函数,它只是一个引用现有getCode方法的lambda 表达式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;
Run Code Online (Sandbox Code Playgroud)

有了这个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;
Run Code Online (Sandbox Code Playgroud)

您可以看到匿名 lambda 函数是通过 调用的invokestatic,而引用的方法是通过 调用的invokevirtual