Java相当于Python中的函数映射

在python中,如果我有一些我想基于输入调用的函数,我可以这样做:

lookup = {'function1':function1, 'function2':function2, 'function3':function3} lookup[input]() 

那就是我有一个映射到该函数的函数名字典,并通过字典查找来调用该函数。

如何在java中执行此操作?

有几种方法可以解决这个问题。 其中大部分已经发布:

  • 命令 – 在地图中保留一堆具有execute()或invoke()方法的对象; 按名称查找命令,然后调用该方法。
  • 多态性 – 比命令更常见,您可以在任何相关的对象集上调用方法。
  • 最后有reflection – 您可以使用reflection来获取对java.lang.Method对象的引用。 对于一组已知的类/方法,这可以很好地工作,并且在加载Method对象后没有太多开销。 例如,您可以使用它来允许用户在命令行中键入java代码,您可以实时执行该命令行。

我个人会使用Command方法。 命令与模板方法完美结合,允许您在所有命令对象上强制执行某些模式。 例:

 public abstract class Command { public final Object execute(Map args) { // do permission checking here or transaction management Object retval = doExecute(args); // do logging, cleanup, caching, etc here return retval; } // subclasses override this to do the real work protected abstract Object doExecute(Map args); } 

只有当你需要对那些你无法控制的设计的类使用这种映射时,我才会求助于reflection,并且这对于编写命令是不切实际的。 例如,您无法通过为每个方法创建命令来在命令shell中公开Java API。

Java没有一流的方法,所以命令模式是你的朋友……

disclamer:代码未经测试!

 public interface Command { void invoke(); } Map commands = new HashMap(); commands.put("function1", new Command() { public void invoke() { System.out.println("hello world"); } }); commands.get("function1").invoke(); 

您可以使用Map 或Map 等,然后使用map.get(“function1”)。invoke(…)。 但通常使用多态而不是查找来更清晰地解决这些问题。

多态的例子..

 public interface Animal {public void speak();}; public class Dog implements Animal {public void speak(){System.out.println("treat? treat? treat?");}} public class Cat implements Animal {public void speak(){System.out.println("leave me alone");}} public class Hamster implements Animal {public void speak(){System.out.println("I run, run, run, but never get anywhere");}} Map animals = new HashMap(); animals.put("dog",new Dog()); animals.put("cat",new Cat()); animals.put("hamster",new Hamster()); for(Animal animal : animals){animal.speak();} 

遗憾的是,Java没有一流的function,但请考虑以下接口:

 public interface F { public B f(A a); } 

这会将类型A到类型B函数类型建模为可以传递的第一类值。 你想要的是Map>

Functional Java是一个以一流函数为中心的相当完整的库。

正如其他问题中所提到的,具有匿名内部类的Map是一种冗长的方法。

一种变体是使用枚举代替匿名内部类。 枚举的每个常量都可以实现/覆盖枚举或实现接口的方法,与匿名内部类技术非常相似,但稍微少一些。 我相信Effective Java 2nd Ed处理如何初始化枚举地图。 要从枚举名称映射,只需要调用MyEnumType.valueOf(name)

正如其他人所说,Java不支持作为第一级对象的function。 为此,您可以使用Functor,它是一个包装函数的类。 Steve Yegge对此有一个很好的咆哮 。

为了帮助您解决这个问题,人们编写了函子库: jga , Commons Functor