J'ai une liste de commandes (i, h, t, etc.) que l'utilisateur entrera sur une ligne de commande/terminal Java. Je voudrais stocker un hachage de commande/méthode paires:
'h', showHelp()
't', teleport()
Pour que je puisse avoir du code comme:
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().
Est-ce possible? Sinon, quelle est la manière la plus simple de procéder?
Avec lambdas (disponible en Java 8+) nous pouvons le faire comme suit:
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"
}
}
Dans ce cas, j'étais paresseux et j'ai réutilisé l'interface Runnable
, mais on pourrait tout aussi bien utiliser l'interface Command
- que j'ai inventée dans la version Java 7 de la réponse.
Il existe également des alternatives au () -> { ... }
syntaxe. Vous pourriez tout aussi bien avoir des fonctions membres pour help
et teleport
et utiliser YourClass::help
resp. YourClass::teleport
au lieu.
Un grand Aide-mémoire Lambda sur Programming.Guide.
Tutoriel Oracle ici: Les Java Tutorials ™ - Lambda Expressions .
Ce que vous voulez vraiment faire, c'est créer une interface, nommée par exemple Command
(ou réutiliser par exemple Runnable
), et laissez votre carte être du type Map<Character, Command>
. Comme ça:
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"
}
}
Cela dit, vous pouvez réellement faire ce que vous demandez (en utilisant la réflexion et la classe Method
.)
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");
}
}
Bien que vous puissiez stocker des méthodes par réflexion, la façon habituelle de le faire est d'utiliser des objets anonymes qui enveloppent la fonction, c'est-à-dire.
interface IFooBar {
void callMe();
}
'h', new IFooBar(){ void callMe() { showHelp(); } }
't', new IFooBar(){ void callMe() { teleport(); } }
HashTable<IFooBar> myHashTable;
...
myHashTable.get('h').callMe();
Si vous utilisez JDK 7, vous pouvez désormais utiliser des méthodes par expression lambda tout comme .net.
Sinon, la meilleure façon est de créer un objet fonction:
public interface Action { void performAction(); }
Hashmap<string,Action> cmdList;
if(!cmdList.containsKey('h'))
System.out.print("No such command.") else cmdList.getValue('h').performAction();