草庐IT

除非指定参数类型,否则 Java 无法编译通用 lambda 参数

coder 2024-03-20 原文

在测试时,我将我的 Junit 升级到 5.0(因此用新版本替换了我的一些 assertTrue() 方法)。这样做之后,我发现我的一个测试没有编译。我将问题简化为没有 junit 或其他依赖项的普通旧 java。结果是以下无法编译的代码:

  public static void recreate() {
    // This does NOT work
    Recreation.assertTrue(identity((x) -> Boolean.TRUE)); 
    // This DOES work
    Recreation.assertTrue(identity((String x) -> Boolean.TRUE)); 
  }

  private static class Recreation {
    public static void assertTrue(boolean b) {
      System.out.println("boolean argument: " + b);
    }

    // If this method is removed, the code will compile. 
    public static void assertTrue(Supplier<Boolean> booleanSupplier) {
      System.out.println("supplier argument: " + booleanSupplier.toString());
    }
  }

  private static <K> K identity(Function<String, K> function) {
    return function.apply("hello");
  }

如上例所示,如果满足以下任一条件,代码将通过编译:

  1. 指定lambda参数类型

  2. 重载的 assertTrue(Supplier booleanSupplier) 方法被移除

这是类型推断/删除的问题,还是这里可能发生了什么?

构建错误:

Error:(10, 35) incompatible types: inference variable K has incompatible bounds
    lower bounds: java.util.function.Supplier<java.lang.Boolean>,java.lang.Object
    lower bounds: java.lang.Boolean

规范:

openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Ubuntu-3ubuntu114.04ppa1)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Ubuntu-3ubuntu114.04ppa1, mixed mode, sharing)

OS: Ubuntu 14.04.5 LTS

编辑:确认问题也存在于 Java 8 上:

java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
exit status 1
Main.java:10: error: incompatible types: inferred type does not conform to upper bound(s)
    Recreation.assertTrue(identity((x) -> Boolean.TRUE));
                                  ^
    inferred: Boolean
    upper bound(s): Supplier<Boolean>,Object
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

最佳答案

环顾四周并阅读此处的 Java 语言规范后 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.1

我认为这里有两个步骤:

首先,重载解析无法推断出 identity((x) -> Boolean.TRUE) 的类型因为它是隐式的 lambda,我认为为了简单起见,它没有被考虑在内。因此,它将扩大参数搜索和使用 public static void assertTrue(Supplier<Boolean> booleanSupplier) .

其次,重载解析完成后,类型推断 开始。这次它真正检查了推断类型,即 Boolean。 , 因为它与 Supplier<Boolean> booleanSupplier 不兼容,你会得到编译错误。

和之前的回答一样,有解决办法,

例如

Recreation.assertTrue(identity((x) -> () -> Boolean.TRUE));

我在这里找到了很好的解释:Java8: ambiguity with lambdas and overloaded methods

关于除非指定参数类型,否则 Java 无法编译通用 lambda 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55483445/

有关除非指定参数类型,否则 Java 无法编译通用 lambda 参数的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  7. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  10. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

随机推荐