Java 中最接近函数指针的替代品是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/122407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the nearest substitute for a function pointer in Java?
提问by Bill the Lizard
I have a method that's about ten lines of code. I want to create more methods that do exactly the same thing, except for a small calculation that's going to change one line of code. This is a perfect application for passing in a function pointer to replace that one line, but Java doesn't have function pointers. What's my best alternative?
我有一个大约十行代码的方法。我想创建更多做完全相同事情的方法,除了会改变一行代码的小计算。这是传入函数指针以替换该行的完美应用程序,但 Java 没有函数指针。我最好的选择是什么?
采纳答案by sblundy
Anonymous inner class
匿名内部类
Say you want to have a function passed in with a String
param that returns an int
.
First you have to define an interface with the function as its only member, if you can't reuse an existing one.
假设您想要传入一个带有String
返回int
.
首先,如果您不能重用现有的接口,您必须定义一个以函数为唯一成员的接口。
interface StringFunction {
int func(String param);
}
A method that takes the pointer would just accept StringFunction
instance like so:
一个接受指针的方法只会接受这样的StringFunction
实例:
public void takingMethod(StringFunction sf) {
int i = sf.func("my string");
// do whatever ...
}
And would be called like so:
并且会像这样被调用:
ref.takingMethod(new StringFunction() {
public int func(String param) {
// body
}
});
EDIT:In Java 8, you could call it with a lambda expression:
编辑:在 Java 8 中,您可以使用 lambda 表达式调用它:
ref.takingMethod(param -> bodyExpression);
回答by Blair Conrad
For each "function pointer", I'd create a small functor classthat implements your calculation. Define an interface that all the classes will implement, and pass instances of those objects into your larger function. This is a combination of the "command pattern", and "strategy pattern".
对于每个“函数指针”,我会创建一个小函子类来实现您的计算。定义一个所有类都将实现的接口,并将这些对象的实例传递给更大的函数。这是“命令模式”和“策略模式”的组合。
@sblundy's example is good.
@sblundy 的例子很好。
回答by rcreswick
You need to create an interface that provides the function(s) that you want to pass around. eg:
您需要创建一个接口来提供您想要传递的功能。例如:
/**
* A simple interface to wrap up a function of one argument.
*
* @author rcreswick
*
*/
public interface Function1<S, T> {
/**
* Evaluates this function on it's arguments.
*
* @param a The first argument.
* @return The result.
*/
public S eval(T a);
}
Then, when you need to pass a function, you can implement that interface:
然后,当您需要传递一个函数时,您可以实现该接口:
List<Integer> result = CollectionUtilities.map(list,
new Function1<Integer, Integer>() {
@Override
public Integer eval(Integer a) {
return a * a;
}
});
Finally, the map function uses the passed in Function1 as follows:
最后,map函数使用传入的Function1如下:
public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn,
Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
Set<K> keySet = new HashSet<K>();
keySet.addAll(m1.keySet());
keySet.addAll(m2.keySet());
results.clear();
for (K key : keySet) {
results.put(key, fn.eval(m1.get(key), m2.get(key)));
}
return results;
}
You can often use Runnable instead of your own interface if you don't need to pass in parameters, or you can use various other techniques to make the param count less "fixed" but it's usually a trade-off with type safety. (Or you can override the constructor for your function object to pass in the params that way.. there are lots of approaches, and some work better in certain circumstances.)
如果您不需要传入参数,您通常可以使用 Runnable 而不是您自己的接口,或者您可以使用各种其他技术使参数计数不那么“固定”,但这通常是与类型安全的权衡。(或者你可以覆盖你的函数对象的构造函数以这种方式传递参数......有很多方法,有些在某些情况下效果更好。)
回答by Dave L.
You may also be interested to hear about work going on for Java 7 involving closures:
您可能也有兴趣了解 Java 7 中涉及闭包的工作:
What's the current state of closures in Java?
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
回答by Dennis S
Sounds like a strategy pattern to me. Check out fluffycat.com Java patterns.
对我来说听起来像是一种策略模式。查看 fluffycat.com Java 模式。
回答by TofuBeer
You can also do this (which in some RAREoccasions makes sense). The issue (and it is a big issue) is that you lose all the typesafety of using a class/interface and you have to deal with the case where the method does not exist.
你也可以这样做(这在一些罕见的情况下是有意义的)。问题(这是一个大问题)是您失去了使用类/接口的所有类型安全性,并且您必须处理该方法不存在的情况。
It does have the "benefit" that you can ignore access restrictions and call private methods (not shown in the example, but you can call methods that the compiler would normally not let you call).
它确实具有“好处”,您可以忽略访问限制并调用私有方法(示例中未显示,但您可以调用编译器通常不允许您调用的方法)。
Again, it is a rare case that this makes sense, but on those occasions it is a nice tool to have.
同样,这是一种有意义的罕见情况,但在这些情况下,它是一个很好的工具。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main
{
public static void main(final String[] argv)
throws NoSuchMethodException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
final String methodName;
final Method method;
final Main main;
main = new Main();
if(argv.length == 0)
{
methodName = "foo";
}
else
{
methodName = "bar";
}
method = Main.class.getDeclaredMethod(methodName, int.class);
main.car(method, 42);
}
private void foo(final int x)
{
System.out.println("foo: " + x);
}
private void bar(final int x)
{
System.out.println("bar: " + x);
}
private void car(final Method method,
final int val)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
method.invoke(this, val);
}
}
回答by Peter Lawrey
If you have just one line which is different you could add a parameter such as a flag and a if(flag) statement which calls one line or the other.
如果您只有一行不同,您可以添加一个参数,例如一个标志和一个调用一行或另一行的 if(flag) 语句。
回答by javashlook
When there is a predefined number of different calculations you can do in that one line, using an enum is a quick, yet clear way to implement a strategy pattern.
当您可以在一行中进行预定义数量的不同计算时,使用枚举是实现策略模式的一种快速而清晰的方法。
public enum Operation {
PLUS {
public double calc(double a, double b) {
return a + b;
}
},
TIMES {
public double calc(double a, double b) {
return a * b;
}
}
...
public abstract double calc(double a, double b);
}
Obviously, the strategy method declaration, as well as exactly one instance of each implementation are all defined in a single class/file.
显然,策略方法声明以及每个实现的一个实例都定义在单个类/文件中。
回答by Mario Fusco
Check out lambdaj
查看 lambdaj
http://code.google.com/p/lambdaj/
http://code.google.com/p/lambdaj/
and in particular its new closure feature
特别是它的新关闭功能
http://code.google.com/p/lambdaj/wiki/Closures
http://code.google.com/p/lambdaj/wiki/Closures
and you will find a very readable way to define closure or function pointer without creating meaningless interface or use ugly inner classes
你会发现一种非常易读的方式来定义闭包或函数指针,而无需创建无意义的接口或使用丑陋的内部类
回答by Lawrence Dol
One of the things I really miss when programming in Java is function callbacks. One situation where the need for these kept presenting itself was in recursively processing hierarchies where you want to perform some specific action for each item. Like walking a directory tree, or processing a data structure. The minimalist inside me hates having to define an interface and then an implementation for each specific case.
用 Java 编程时我真正怀念的一件事是函数回调。需要这些不断出现的一种情况是递归处理层次结构,您希望为每个项目执行某些特定操作。就像遍历目录树或处理数据结构一样。我内心的极简主义者讨厌必须定义一个接口,然后为每个特定情况定义一个实现。
One day I found myself wondering why not? We have method pointers - the Method object. With optimizing JIT compilers, reflective invocation really doesn't carry a huge performance penalty anymore. And besides next to, say, copying a file from one location to another, the cost of the reflected method invocation pales into insignificance.
有一天,我发现自己在想为什么不呢?我们有方法指针——Method 对象。通过优化 JIT 编译器,反射调用确实不再带来巨大的性能损失。除了将文件从一个位置复制到另一个位置之外,反射方法调用的成本变得微不足道。
As I thought more about it, I realized that a callback in the OOP paradigm requires binding an object and a method together - enter the Callback object.
当我想得更多时,我意识到 OOP 范式中的回调需要将一个对象和一个方法绑定在一起——输入回调对象。
Check out my reflection based solution for Callbacks in Java. Free for any use.
查看我的基于反射的Java 回调解决方案。免费供任何使用。