[英]Java - how do I pass a method as parameter?
I have a stanza of code that is repeatedly used. 我有一个重复使用的代码节。 Here are two examples: 这是两个例子:
public java.sql.Struct createStruct(String typeName, Object[] attributes) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Struct ret = delegate().createStruct(name.toLowerCase(), attributes);
setSearchPath(searchPath);
return ret;
}
public java.sql.Array createArray(String typeName, Object[] elements) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Array ret = delegate().createArray(name.toLowerCase(), elements);
setSearchPath(searchPath);
return ret;
}
You can see that these two methods have the general form: 您可以看到这两种方法具有一般形式:
public <T> createXXX(String typeName, Object[] objects) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = delegate().createXXX(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
Where T
is the return type of some set of functions createXXX
that have a common signature but different return type. 其中T
是某些函数集createXXX
的返回类型,它们具有共同的签名但返回类型不同。
I'm pretty sure how I would do this in Javascript, F#, C#, Scala or any number of other languages. 我非常确定如何在Javascript,F#,C#,Scala或其他许多语言中执行此操作。
I just can't seem to wrap my head around how to do this in Java in a type-safe manner that allows me to call each createXXX
method so that the setup and tear-down can happen in one block of code, rather than sprinkled throughout each wrapper method. 我似乎无法以类型安全的方式围绕如何在Java中执行此操作,这允许我调用每个createXXX
方法,以便设置和拆除可以在一个代码块中发生,而不是撒上贯穿每个包装器方法。
I know I could use reflection, but am looking for a way to do this using lambdas, if possible, or whatever structure makes the most sense in Java. 我知道我可以使用反射,但我正在寻找一种方法来使用lambdas,如果可能的话,或者在Java中最有意义的结构。
Something like this, where the method to be called is passed as the third parameter (I know this code is completely malformed in Java): 像这样的东西,其中要调用的方法作为第三个参数传递(我知道这个代码在Java中完全格式错误):
public Struct createStruct(String typeName, Object[] attributes) {
return createTypeWithCorrectSearchPath<>(
typeName,
attributes,
delegate().createStruct
);
}
public Struct createArray(String typeName, Object[] elements) {
return createTypeWithCorrectSearchPath<>(
typeName,
elements,
delegate().createArray
);
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
[SOME-METHOD-HERE]) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = [SOME-METHOD-HERE](name, objects);
setSearchPath(searchPath);
return ret;
}
I've read the apparently duplicate questions: 我已经阅读了明显重复的问题:
As well as some questions about method references with generics: 以及有关泛型的方法引用的一些问题:
For whatever reason it's not gelling for me, so I'm risking asking a question that will immediately be marked as duplicate in the hopes that someone will take pity and help me out... 无论出于何种原因,它不会给我带来任何影响,所以我冒着问一个会立即被标记为重复的问题,希望有人会怜惜并帮助我...
UPDATE 2015-02-06 更新2015-02-06
While both Louis Wasserman and Neuron gave basically the same answer, it was Louis that more pedantically offered a pattern that worked best for me... with an explicit example of how to pass the method reference . 虽然Louis Wasserman和Neuron给出了基本相同的答案,但路易斯更迂腐地提供了一种最适合我的模式......以及如何传递方法参考的明确示例。
Here's what ended up working for me: 以下是最终为我工作的内容:
interface SearchPathCreator<T> {
T create(String typeName, Object[] objects) throws SQLException;
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
SearchPathCreator<?> creator) throws SQLException {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
//noinspection unchecked
T ret = (T) creator.create(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
Which is called just like Louis suggested: 就像路易斯建议的那样:
public Struct createStruct(
String typeName,
Object[] attributes) throws SQLException {
return createTypeWithCorrectSearchPath(
typeName,
attributes,
delegate()::createStruct
);
}
interface MyMethodType<T> {
T method(String name, Object[] objects);
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
MyMethodType<T> impl) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = impl.method(name, objects);
setSearchPath(searchPath);
return ret;
}
createTypeWithCorrectSearchPath(typeName, objects, delegate()::createStruct);
The crucial bits are a) creating your own interface type, though I suppose you could use BiFunction<String, Object[]>
, b) using method references with ::
. 关键的一点是a)创建自己的接口类型,虽然我想你可以使用BiFunction<String, Object[]>
,b)使用带有::
方法引用。
You can solve this problem by passing objects which have the sole purpose of performing that one function. 您可以通过传递唯一目的来执行该功能的对象来解决此问题。 Here is a little example to you give you an idea. 这是一个给你一个想法的小例子。 Create an interface for the type of function. 为函数类型创建一个接口。 You need to use generics as I did here: 你需要像我在这里一样使用泛型:
public interface Creator<A>{
A create(String name, Object[] attributes);
}
Then define your method which takes functions of the type you just specified: 然后定义你的方法,它接受你刚才指定的类型的函数:
public <A> A create(String typeName, Object[] attributes, Creator<A> creator){
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
A ret = creator.create(name.toLowerCase(), attributes);
setSearchPath(searchPath);
return ret;
}
The most convenient way are anonymous classes where you define the interfaces implementation in line: 最方便的方法是匿名类,您可以在其中定义接口实现:
java.sql.Struct struct = create("foo bar", new Object[]{"att1", "att2"}, new Creator<Struct>() {
@Override
public Struct create(String name, Object[] attributes) {
return //your implementation..
}
})
if you can't put the implementation into an anonymous class, because you need to access delegate().createXXX(...)
, simply put the definition of the class implementing the interface into the a scope where your method becomes accessible. 如果您不能将实现放入匿名类中,因为您需要访问delegate().createXXX(...)
,只需将实现该接口的类的定义放入您的方法可访问的范围内。
Louis' answer is on the right track; 路易斯的回答是正确的; however, it's not clear to me that delegate()
would be available at the point where the create method is called. 但是,我不清楚delegate()
是否可以在调用create方法的位置使用。 If it isn't available, then you'll need a three-argument interface method. 如果它不可用,那么你需要一个三参数接口方法。
I don't know what type delegate()
returns, but suppose it's Delegate
. 我不知道delegate()
返回什么类型,但假设它是Delegate
。 One thing to note is that if Delegate
has an instance method createArray(String s, Object[] objects)
, you can use Delegate::createArray
as a method reference for a functional interface for a function with three arguments. 需要注意的一点是,如果Delegate
具有实例方法createArray(String s, Object[] objects)
,则可以使用Delegate::createArray
作为具有三个参数的函数的功能接口的方法引用。 The first argument would be a Delegate
. 第一个参数是一个Delegate
。 Thus: 从而:
interface MyMethodType<T> {
T method(Delegate delegate, String name, Object[] objects);
}
Now, in your createTypeWithCorrectSearchPath
method, you would call the interface like this: 现在,在createTypeWithCorrectSearchPath
方法中,您可以像这样调用接口:
impl.method(delegate(), name.toLowerCase(), objects);
The first parameter of the call would become the instance on which the two-argument instance method operates. 调用的第一个参数将成为双参数实例方法操作的实例。 That is, if the actual parameter is Delegate::createArray
, it would be called like 也就是说,如果实际参数是Delegate::createArray
,则会调用它
delegate().createArray(name.toLowerCase(), objects);
Unlike in Louis' answer, you have to define your own interface here, because there's no built-in TriFunction
class in Java 8. 与Louis的回答不同,你必须在这里定义自己的接口,因为Java 8中没有内置的TriFunction
类。
See Section 15.13.3 of the JLS for a complete description of how method references can be used. 有关如何使用方法引用的完整说明,请参见JLS的第15.13.3节 。 This particular one is listed in the paragraph starting "If the form is ReferenceType :: [TypeArguments] Identifier ". 这个特定的一个列在开头“如果表单是ReferenceType :: [TypeArguments] Identifier ”的段落中 。
EDIT: After taking another look at the question, I see that createTypeWithCorrectSearchPath
was intended to be a private method, and not called from the outside. 编辑:再看看这个问题后,我看到createTypeWithCorrectSearchPath
是一个私有方法,而不是从外部调用。 So this answer probably isn't applicable. 所以这个答案可能不适用。 I'm leaving it here, though, because it might be a useful answer in some similar situations. 不过,我将它留在这里,因为在某些类似情况下它可能是一个有用的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.