How to call a method stored in a HashMap? (Java)
Solution 1
With Java 8+ and Lambda expressions
With lambdas (available in Java 8+) we can do it as follows:
class Test {
public static void main(String[] args) throws Exception {
Map<Character, Runnable> commands = new HashMap<>();
// Populate commands map
commands.put('h', () -> System.out.println("Help"));
commands.put('t', () -> System.out.println("Teleport"));
// Invoke some command
char cmd = 't';
commands.get(cmd).run(); // Prints "Teleport"
}
}
In this case I was lazy and reused the Runnable
interface, but one could just as well use the Command
-interface that I invented in the Java 7 version of the answer.
Also, there are alternatives to the () -> { ... }
syntax. You could just as well have member functions for help
and teleport
and use YourClass::help
resp. YourClass::teleport
instead.
A great Lambda cheat sheet over at Programming.Guide.
Oracle tutorial here: The Java Tutorials™ – Lambda Expressions.
Java 7 and below
What you really want to do is to create an interface, named for instance Command
(or reuse for instance Runnable
), and let your map be of the type Map<Character, Command>
. Like this:
import java.util.*;
interface Command {
void runCommand();
}
public class Test {
public static void main(String[] args) throws Exception {
Map<Character, Command> methodMap = new HashMap<Character, Command>();
methodMap.put('h', new Command() {
public void runCommand() { System.out.println("help"); };
});
methodMap.put('t', new Command() {
public void runCommand() { System.out.println("teleport"); };
});
char cmd = 'h';
methodMap.get(cmd).runCommand(); // prints "Help"
cmd = 't';
methodMap.get(cmd).runCommand(); // prints "teleport"
}
}
Reflection "hack"
With that said, you can actually do what you're asking for (using reflection and the Method
class.)
import java.lang.reflect.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
Map<Character, Method> methodMap = new HashMap<Character, Method>();
methodMap.put('h', Test.class.getMethod("showHelp"));
methodMap.put('t', Test.class.getMethod("teleport"));
char cmd = 'h';
methodMap.get(cmd).invoke(null); // prints "Help"
cmd = 't';
methodMap.get(cmd).invoke(null); // prints "teleport"
}
public static void showHelp() {
System.out.println("Help");
}
public static void teleport() {
System.out.println("teleport");
}
}
Solution 2
Though you could store methods through reflection, the usual way to do it is to use anonymous objects that wrap the function, i.e.
interface IFooBar {
void callMe();
}
'h', new IFooBar(){ void callMe() { showHelp(); } }
't', new IFooBar(){ void callMe() { teleport(); } }
HashTable<IFooBar> myHashTable;
...
myHashTable.get('h').callMe();
Solution 3
If you are using JDK 7 you can now use methods by lambda expression just like .net.
If Not the best way is to make a Function Object:
public interface Action { void performAction(); }
Hashmap<string,Action> cmdList;
if (!cmdList.containsKey('h')) {
System.out.print("No such command.")
} else {
cmdList.getValue('h').performAction();
}
![cwhiii](https://i.stack.imgur.com/49jRK.jpg?s=256&g=1)
cwhiii
Everything you could want to know is just a click away; just go look at the page on my website.
Updated on July 05, 2022Comments
-
cwhiii almost 2 years
I have a list of commands (i, h, t, etc) that the user will be entering on a command line/terminal Java program. I would like to store a hash of command/method pairs:
'h', showHelp() 't', teleport()
So that I can have code something like:
HashMap cmdList = new HashMap(); cmdList.put('h', showHelp()); if(!cmdList.containsKey('h')) System.out.print("No such command.") else cmdList.getValue('h') // This should run showHelp().
Is this possible? If not, what is an easy way to this?
-
9000 over 13 yearsNo support for first-class functions is such a nuisance :)
-
Stephen C over 13 yearsActually, lambda expressions have been deferred to JDK 8.
-
Noel M over 13 years
-
fatih tekin over 10 yearsi think that is thread safe but i am not sure do you agree that it is thread safe
-
aioobe over 10 yearsI would suspect that the
get
operation is thread safe. But to be sure you might want to useCollections.synchronizedMap
. -
aioobe over 10 years@9000, answer updated! :-)
-
Tano almost 8 years@aioobe sorry if my question is stupid but what will be the runtime for the first example with Java 8
-
aioobe almost 8 years@imoteb, could you clarify your question? Are you asking about the runtime types? The performance?
-
nullpointer about 6 yearsHow to pass arguments?
-
aioobe about 6 yearsIf
Runnable.run
would have accepted arguments, it would have beencommands.get(cmd).run(some, args, here)
.run()
is not part of the lambda-story. It's simply the method on theRunnable
interface. -
Eduardo Teixeira over 3 yearsReflection "hack" works like a charm, if someone need pass parameters: "methodMap.put('h', Test.class.getMethod("showHelp", String.class));" and "methodMap.get(cmd).invoke(null, "myParam");"
-
Steven over 2 yearsThe major part of the hashMap function map is that we want to call it later with arguments, anyone could provide the sample contains the parameters, i.g. int func(string p1, int 2) and when I build the hashMap<event, func>, I don't know the value, and when the event happen, I call hashmap.get(event).func("now", -1).