Java(或Groovy)中类似于Scala的apply方法的等效方法

3
在Scala中,如果有一个对象Foo具有apply(x:Int),则可以使用Foo(42)来调用它(作为Foo.apply(42)的简写)。
是否可能在Java或Groovy中复制这个功能?我曾认为Groovy的call会起相似的作用,但是def call(int x)static def call(int x)都没有调用call编辑:添加所请求的DSL示例
现有的典型DSL:alter 't' add 'a' storing BAR (其中BAR是枚举类型)。 尝试添加一个将取代上述内容中的BAR但将接受参数的内容,但不要使语法过于不同,理想情况下为:alter 't' add 'a' storing FOO(42) 我已经创建了一个具有接受int参数的构造函数的类FOO - 现在我正在寻找一种通过FOO(42)而不是 new FOO(42) FOO.call(42)来调用该构造函数的方法。

酷的问题,你能提供更多信息吗? - Kick Buttowski
@KickButtowski 这是针对 DSL 的,通常情况下会调用枚举,但需要添加一个带参数的内容,因此它被实现为类而不是枚举。但理想情况下,我希望在这种特殊情况下保持 DSL 语法与其他情况尽可能接近。FOO(42)new FOO(42)FOO.call(42)更接近于 FOO - frostmatthew
@WillP 添加了示例 DSL。 - frostmatthew
@BillK DSL允许开发人员编写与数据库无关的SQL,然后将其映射到多个数据库的特定SQL - 对我来说,这似乎是DSL的一个很好的用途。此外,编写/使用DSL也不是一个选项,毕竟我是一名非常初级的工程师,在一个非常大的企业中 :-) - frostmatthew
@DaveNewton 我是Scala的超级粉丝,但显然为了一行代码使用一种语言的特性而重写整个项目是不明智的。此外,正如我在之前的评论中提到的“我是一个非常初级的工程师,在一个非常大的企业中” - 我们为一个项目使用哪种语言并不完全取决于我。 - frostmatthew
显示剩余4条评论
2个回答

3

在Groovy中,一个简单的方法是在类上编写static call()方法,但这并不能使 Clazz() 正常工作。可能是个bug,但我找不到相关的JIRA。

我想建议使用闭包:

import groovy.transform.Canonical as C

@C class Bar { def bar }

@C class Baz { def baz }

A = { new Bar(bar: it) }

B = { new Baz(baz: it) }


assert A("wot") == new Bar(bar: "wot")
assert B("fuzz") == new Baz(baz: "fuzz")

更新: 看起来类名在被调用者上下文中解析为静态方法调用,这样可以工作(但在DSL中无法使用):

class A { 
    static call(str) { str.toUpperCase() } 
}
assert ((Class)A)("qwop") == "QWOP"

更新2:根据您的DSL示例,去掉括号是否可行?
class FOO {}


def params = [:]

alter = { 
  params.alter = it
  [add : { 
      params.add = it
      [storing: { 
          params.clazz = it
          [:].withDefault { params.param = it }
      }]
  }]
}


alter 't' add 'a' storing FOO 42


assert params == [
  alter : 't',
  add   : 'a',
  clazz : FOO,
  param : '42'
]

1
使用@Canonical非常完美。 :) - dmahapatro
移除括号完全没问题 - 但你的示例重写了整个领域特定语言,这绝对不行。我需要一个完全独立于其他任何东西处理 FOO 42 部分的解决方案。 - frostmatthew
@Exupery是使用闭包的第一个例子,是否合适? - Will
是的,带有闭包的那个更合适!很抱歉昨天没有注意到 - 我觉得我没有一个好地方来放置类似于 A = { new Bar(bar: it) } 的等价物,但是再次查看它后,我意识到我可以将其放在枚举的静态方法中(保存所有其他/正常的“FOOs”),并将该方法命名为 FOO。然后我当然意识到我可以在该方法中添加 return new FOO(x),哈。感谢您让我走上了正确的道路![而且您的答案确实回答了我的问题的通用/原始形式] - frostmatthew
call() 也适用于枚举类型,如果有帮助的话:enum P { E; def call() { "wot" } }; assert P.E() == "wot" - Will

0

Groovy 中的 Closure 有一个可以省略的方法 call()

def action = { a, b = 1 -> println "$a and $b" }
action.call 1 // prints "1 and 1"
action( 1, 3 ) // prints "1 and 3"

在Java中,最接近的替代方案是Runnable:它提供了无参的run()方法,但不能简写。

1
也适用于类 class Foo { def call(x) { println x } }; foo = new Foo(); foo(42) - cfrick
2
@cfrick的评论应该作为一个答案。 - dmahapatro
@cfrick 这在静态 call 中能行吗?我只是想知道这里是否可能使用完全相同的 Scala 语法。 - Opal
@cfrick,这更接近我想要的,但需要在不实例化Foo的情况下完成。 - frostmatthew
@Opal似乎不能简单地添加“static”来解决。另外,第一眼看起来call.metaClass.Foo也不起作用。 - cfrick
@cfrick,确实,我尝试过使用 method.invokeStaticMethodclass A { static call(){} } 以及 doCall,但都失败了。 - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接