简体   繁体   English

Java相当于Python中的函数映射

[英]Java equivalent of function mapping in Python

In python, if I have a few functions that I would like to call based on an input, i can do this: 在python中,如果我有一些我想根据输入调用的函数,我可以这样做:

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

That is I have a dictionary of function name mapped to the function, and call the function by a dictionary lookup. 那就是我有一个映射到该函数的函数名字典,并通过字典查找来调用该函数。

How to do this in java? 如何在java中执行此操作?

Java doesn't have first-class methods, so the command pattern is your friend... Java没有一流的方法,所以命令模式是你的朋友......

disclamer: code not tested! disclamer:代码未经测试!

public interface Command 
{
    void invoke();
}

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

commands.get("function1").invoke();

There are several ways to approach this problem. 有几种方法可以解决这个问题。 Most of these were posted already: 其中大部分已经发布:

  • Commands - Keep a bunch of objects that have an execute() or invoke() method in a map; 命令 - 在地图中保留一堆具有execute()或invoke()方法的对象; lookup the command by name, then invoke the method. 按名称查找命令,然后调用该方法。
  • Polymorphism - More generally than commands, you can invoke methods on any related set of objects. 多态性 - 比命令更常见,您可以在任何相关的对象集上调用方法。
  • Finally there is Reflection - You can use reflection to get references to java.lang.Method objects. 最后有反射 - 您可以使用反射来获取对java.lang.Method对象的引用。 For a set of known classes/methods, this works fairly well and there isn't too much overhead once you load the Method objects. 对于一组已知的类/方法,这非常有效,并且在加载Method对象后没有太多开销。 You could use this to, for example, allow a user to type java code into a command line, which you execute in real time. 例如,您可以使用它来允许用户在命令行中键入java代码,您可以实时执行该命令行。

Personally I would use the Command approach. 我个人会使用Command方法。 Commands combine well with Template Methods , allowing you to enforce certain patterns on all your command objects. 命令与模板方法完美结合,允许您在所有命令对象上强制执行某些模式。 Example: 例:

public abstract class Command {
  public final Object execute(Map<String, Object> 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<String, Object> args);
}

I would resort to reflection only when you need to use this kind of mapping for classes whose design you don't control, and for which it's not practical to make commands. 只有当你需要对那些你无法控制的设计的类使用这种映射时,我才会求助于反射,并且这对于编写命令是不切实际的。 For example, you couldn't expose the Java API in a command-shell by making commands for each method. 例如,您无法通过为每个方法创建命令来在命令shell中公开Java API。

You could use a Map<String,Method> or Map<String,Callable> etc,and then use map.get("function1").invoke(...). 您可以使用Map <String,Method>或Map <String,Callable>等,然后使用map.get(“function1”)。invoke(...)。 But usually these kinds of problems are tackled more cleanly by using polymorphism instead of a lookup. 但通常使用多态而不是查找来更清晰地解决这些问题。

Polymorphic example.. 多态的例子..

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<String,Animal> animals = new HashMap<String,Animal>();
animals.put("dog",new Dog());
animals.put("cat",new Cat());
animals.put("hamster",new Hamster());
for(Animal animal : animals){animal.speak();}

Unfortunately, Java does not have first-class functions, but consider the following interface: 遗憾的是,Java没有一流的功能,但请考虑以下界面:

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

This models the type for functions from type A to type B , as first-class values that you can pass around. 这会为类型A到类型B函数类型建模,作为可以传递的第一类值。 What you want is a Map<String, F<A, B>> . 你想要的是Map<String, F<A, B>>

Functional Java is a fairly complete library centered around first-class functions. Functional Java是一个以一流函数为中心的相当完整的库。

As mentioned in other questions, a Map<String,MyCommandType> with anonymous inner classes is one verbose way to do it. 正如其他问题中所提到的,具有匿名内部类的Map<String,MyCommandType>是一种冗长的方法。

A variation is to use enums in place of the anonymous inner classes. 一种变体是使用枚举代替匿名内部类。 Each constant of the enum can implement/override methods of the enum or implemented interface, much the same as the anonymous inner class technique but with a little less mess. 枚举的每个常量都可以实现/覆盖枚举或实现接口的方法,与匿名内部类技术非常相似,但是稍微少一些。 I believe Effective Java 2nd Ed deals with how to initialise a map of enums. 我相信Effective Java 2nd Ed处理如何初始化枚举地图。 To map from the enum name merely requires calling MyEnumType.valueOf(name) . 要从枚举名称映射,只需要调用MyEnumType.valueOf(name)

As everyone else said, Java doesn't support functions as first-level objects. 正如其他人所说,Java不支持作为第一级对象的功能。 To achieve this, you use a Functor, which is a class that wraps a function. 要实现此目的,请使用Functor,它是一个包装函数的类。 Steve Yegge has a nice rant about that. 史蒂夫·耶格对此有一个很好的咆哮

To help you with this limitation, people write functor libraries: jga , Commons Functor 为了帮助您解决这个限制,人们编写了函子库: jgaCommons Functor

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM