Java: run method based on user input? - java

say I have three methods
method1()
method2()
method3()
and I have the user input a number corresponding to which method they want to run, is there a way to run it directly from their input? i.e. instead of having an if statement along the lines of
System.out.println("Which method would you like to run? 1/2/3");
String input = reader.readLine();
if(input == 1){method1();}
if(input == 2){method2();}
...
etc. and instead be able to have something like
System.out.println("Which method would you like to run? 1/2/3");
String input = reader.readLine();
method(input)();
?

Yes you could achieve that by using an interface as follows:
interface A {
void run();
}
public void method1() {}
public void method2() {}
public void mainMethod(String[] args) {
// Initialise the method map - note, you only have to do this once
// So, this initialisation code can go into a constructor
// And mothodMap can be declared as a final instance variable.
A methodOne = new A() { #Override public void run() { method1(); } };
A methodTwo = new A() { #Override public void run() { method2(); } };
Map<Integer, A> methodMap = new HashMap<>();
methodMap.put(1, methodOne);
methodMap.put(2, methodTwo);
Integer input = /* get it from user*/ 1;
A aMethod = methodMap.get(input);
aMethod.run();
}

No, not unless you use reflection. Java doesn't have function pointers, otherwise you could index to the appropriate function in an array. But what's wrong with if statements? They're more readable and secure..
If you're looking for a future-proof, more abstract solution, consider a strategy pattern:
// strategy
interface CommandMethod {
void runMethod();
}
// for every method 1 .. n
class CmdMethod1() implements CommandMethod {
void runMethod() {
// concrete implementation
}
}
// initialization ----------------
Map<String, CommandMethod> cmds = new HashMap<String, CommandMethod>();
cmds.put("1", new CmdMethod1());
// .. etc ..
cmds.put("n", new CmdMethodN());
// at the prompt:
System.out.println("Which method would you like to run? 1/2/3/.../n");
String input = reader.readLine();
cmds.get(input).runMethod(); // more like what you're going for ?

Not without having an if or switch statement (or reflection like paislee pointed out). If you wanted to do something like method(input); you would need the if/switch statement in another method:
....
String input = reader.readLine();
method(input);
}
private void method(int input) {
if (input == 1) {method1();}
if (input == 2) {method2();}
}

There's no way to do this. However, you can use if-statements or switch-case statements to make the "redirection" process less cumbersome. You might also consider creating a wrapper function to accept the user input to make your code cleaner.

The standard way of accomplishing this is to create a "functor"
public interface Functor
{
public void execute();
}
public class Method1 implements Functor
{
public void execute() { /* do something */ }
}
etc...
private Functor[] f = { new Method1(), new Method2(), new Method3() };
...
// Execute the method selected by i
f[i].execute();
Also take a look at the Callable interface

Just to update this. Another way this can be implemented is by using switch-case in a while true loop. And using scanner object static Scanner scanner = new Scanner(System.in); user input.
while(true){
System.out.print("Input: ");
int option = scanner.nextInt();
switch(option){
case 1 -> method1();
case 2 -> method2();
}
}
do remember to include a way to exit the while loop in any of the methods.

Related

How to make an auto-adding command with interface?

I'm coding something like cmd in java, so I made a few commands like (hello world), , etc. All the commands are classes that implement the interface (I named it as "API"), but to identify which command is written, I use the "if" expression, so to add the new command (class), I have to write this expression every time, for instance:
if (command.equals("print")){return new Print();}
Well, that's the question, how can I write an expression once to make java identify a new command (class), no matter how much I add?
Thanks in advance;
That's the code:
This interface helps the program identify which command is written:
public interface UI {
API get();
Function<String, UI> check = command -> {
if (command.equals("print")){return new Print();}
if (command.equals("change")){return new Change();}
if (command.equals("exit")){return new Exit();}
return new NotFound();
};
static UI of(String command){
return check.apply(command);
}
}
An example of a class:
public class Print extends Backend implements API, UI{
#Override
public boolean command() {
System.out.println(string);
return true;
}
#Override
public API get() {
return new Print();
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean run = true;
while (run) {
System.out.print("Java> ");
//UI
UI command = UI.of(scanner.next());
API com = command.get();
run = com.command();
}
}
}

Is it possible to ask the user to pick what class they'd like to run and then run that class?

I'm new to JAVA programming, and was wondering if it's possible/how to ask the user to input what class they'd like to run and then call/run that class?
Example:
I created two classes to solve the Towers of Hanoi given (supplied by user) n amount of disks. One class solves the puzzle recursively and the other class solves the puzzle iteratively. When I am asking the user for the number of disks they'd like to use, is it possible to ask them how they would like to solve the program whether it be recursively or iteratively and then call the class that they chose?
Yes, that is possible.
This version may look a bit more complicated on first glance, but it separates the parts more clearly. The interface and the classes would usually be in separate files in real applications. Also, the static chooseSolver - method would possible be moved to a separate class named something like SolverFactory.
import java.util.Scanner;
import java.util.Set;
public class Main {
interface Solver {
void solveIt();
}
static class SuperSolver implements Solver {
public void solveIt() {
System.out.println("SuperSolver always solves anything");
}
}
static class FastSolver implements Solver {
public void solveIt() {
System.out.println("Noone beats the FastSolver");
}
}
public static void main(String[] args) {
String in = askUserForOption();
Solver s = chooseSolver(in);
s.solveIt();
}
private static String askUserForOption() {
String in;
Set<String> validOptions = Set.of("A", "B");
try (Scanner sc = new Scanner(System.in)) {
do {
System.out.print("Enter A or B: ");
in = sc.nextLine();
} while (!validOptions.contains(in));
}
return in;
}
private static Solver chooseSolver(String in) {
switch (in) {
case "A":
return new SuperSolver();
case "B":
return new FastSolver();
default:
throw new IllegalArgumentException("something went terribly wrong - an invalid option was given");
}
}
}
You can do this in a pretty straightforward manner using a common interface both solvers implement.
interface HanoiSolver {
void solve(int n);
}
// iterative solver
class IterativeHanoi implements HanoiSolver {
public void solve(int n) { ... }
}
// iterative solver
class RecursiveHanoi implements HanoiSolver {
public void solve(int n) { ... }
}
public class MainClass {
public static void main(String[] args) {
// you can change this to read input however you like
String userInput = args[0];
Integer n = Integer.parseInt(args[1]);
HanoiSolver solver;
if (userInput.equals("recursive")) {
solver = new RecursiveHanoi();
} else {
solver = new IterativeHanoi();
}
solver.solve(n);
}
}
Depends on where this code is used internally or as library package.
Internally you can use interface and then seperate out the concrete implementation.
In library , you can again let user call interface method , write implementation of that interface based on condition.
Or if you want the user to determine the algo to use during the runtime then use Reflection to decide which class's object to create.

Call Methods in Sequence

I have 5 different methods like this
public void met1(){}
public void met2(){}
public void met3(){}
public void met4(){}
public void met5(){}
I want to call this method from 1 to 5 is there any convinient way to do this.
I don't want to call one by one or I don't want to put method call inside other method.
How Can I do this??
I believe you could do it with reflection with something like:
YourClass classInstance = new YourClass();
for (int i = 1; i < 6; i++) {
Method yourMethod = YourClass.class.getMethod("met" + i);
method.invoke(instance);
}
Haven't tested it out, so no guarantees.
Have you looked into fluent design patterns? http://www.javacodegeeks.com/2013/01/fluent-object-creation.html
Example would be something like this:
myObject.met1().met2().met3().met4().met5().result();
You can use the Execute Around Method pattern.
public class Resource {
private Resource(){}
public void opc1(){
System.out.println("Opc1");
// use can use cascade pattern( return this)
}
public void opc2(){
System.out.println("Opc2");
// use can use cascade pattern( return this)
}
public void opc3(){
System.out.println("Opc3");
// use can use cascade pattern( return this)
}
public void closeResource(){
System.out.println("Release resource");
}
public static void use(Consumer<Resource> consumer){
Resource resource =new Resource();
consumer.accept(resource);
resource.closeResource(); // force to execute closeResource method
}
public static void main(String[] args) {
Resource.use(resource -> {
resource.opc1();
resource.opc3();
resource.opc2();
});
}
}
More info at https://agiledeveloper.com/
You could do this with reflection as other answers have previously mentioned. Reflection is generally avoided if possible.
In reality the most common design pattern to address your concern would be Chain of Responsibility.
http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
The only way to call methods by name is through reflection. See this article for how to do this:
How do I invoke a Java method when given the method name as a string?
Something like this should work:
for (int i = 1; i < 6; i++){
java.lang.reflect.Method method;
try {
method = this.getClass().getMethod("met" + i);
method.invoke(this);
} catch (SecurityException e) {
// ...
} catch (NoSuchMethodException e) {
// ...
}
}

Calling another method from a String method after it returns the string

I have something I am trying to figure out. So when I run this method called:
public String showList()
I want it to return the string, but after that call a method called displayMenu, so it will automatically go to the next method when the showList is called. Is this possible?
The showList method: (I want to call another method called public void displayMenu())
public String showList()
{
sortList();
int i = 0;
String retStr = "The nodes in the list are:\n";
LinkedListNode current = front;
while(current != null){
i++;
retStr += "Node " + i + " is: " + current.getData() + "\n";
current = current.getNext();
}
return retStr;
//Would like to call the displayMenu() here, but I can't after the string returns it is unreachable.
}
Note: I don't recommend doing this. I definitely recommend that you call the methods one after another in some controller class. Now that that's done:
A rather complicated method of doing this that hasn't yet been mentioned is by using a Thread. I would not generally do this, but it is worth noting that it can be done. Note that this is dealing with Threads (see tutorial) so I won't guarantee that the method will evaluate after the return.
One way of doing this is as follows:
In the same class as your method include something like the following:
class doSomething implements Runnable{
public void run(){
displayMenu();
}
}
Then, in your showList method, do the following:
public String showList(){
...//some code
(new Thread(new doSomething())).start(); //more efficient: create a
//variable to hold the thread.
return retStr;
}
Example code:
public class test{
public static void main(String[]a){
System.out.print(foo());
}
public static String foo(){
(new Thread(new fooBar())).start();
return "foo";
}
public static void bar(){
System.out.println("bar");
}
static class fooBar implements Runnable{
public void run(){
bar();
}
}
}
Prints:
foobar
you can not write anything after the return statement. Return statement should be the last line of a method.
The thing about a return statement is that when you use it, you're basically saying that "I want to return this value now". Not in 5 lines, not after another function call. Now.
Thus, it doesn't make sense to want to do something in a method after returning a value; you've already basically indicated that there's nothing left to do; you're done and ready to go back to the calling method.
#DarkKnight and #ManZzup have already suggested alternatives; you need to restructure your code so that there's no need for such a construct.
Modify your method calling showList() as shown below. Let's call this method is doSomething()
doSomething(){
String output=showList(..); // This is your existing method call
displayMenu(); // call displaymenu() once showlist() execution is over
}

How to use interface methods randomly?

I have an interface and these methods:
public interface Form {
public void setFirstName (String value);
public void setLastName (String value);
public void setGender (String value);
}
Can I call these methods randomly on an objet? Something like:
form.randomMethodFromFormInterface(String randomString);
Is it actually possible? Just to clarify, I would like to fillout the form randomly: sometimes just the last name, sometimes just the first name, sometimes just the gender.
Random rand = new Random();
switch (rand.nextInt(3)) {
case 0: myForm.setFirstName(myFirstName); break;
case 1: myForm.setLastName(myLastName); break;
case 2: myForm.setGender(myGender); break;
default: throw new IllegalStateException();
}
Couldn't you use Random to pick from 0-2, and then depending on that value call the corresponding method?
Could you make another method in the interface that generates a random number and calls a method based on that number? Although I would bet there's an easier way to do this than creating an interface for it.
Here a general way, using reflection:
private static Random r = new Random();
public static void callRandomMethod(Object target, Class<?> iface, Object ... arguments) {
List<Method> methods = findFittingMethods(iface, arguments);
Method m = methods.get(r.nextInt(methods.size()));
m.invoke(target, arguments);
}
public List<Method> findFittingMethods(Class<?> iface, Object ... arguments
Method[] allMethods = iface.getMethods();
List<Method> fittingMethods = new ArrayList<Method>();
findMethodLoop:
for(Method candidate : allMethods) {
Class<?>[] argumentTypes = candidate.getArguments();
if(argumentTypes.length != arguments.length) {
continue;
}
// check argument types
for(int i = 0; i < argumentTypes.length; i++) {
if(arguments[i] == null) {
if(argumentTypes[i].isPrimitive()) {
// null can't be passed to a primitive argument.
continue findMethodLoop;
}
else {
// ... but to every other argument type.
continue; // check next argument
}
}
if(argumentTypes[i].isInstance(arguments[i])) {
continue; // check next argument
}
if(argumentTypes[i].isPrimitive()) {
// hack to check if we have the right wrapper class
try {
Array.set(Array.newInstance(argumentTypes[i], 1), 0, arguments[i]);
continue; // check next argument
}
catch(ArrayStoreException ex) {
continue findMethodLoop;
}
}
// wrong type
continue findMethodLoop;
}
// now we found a method which would accept the arguments, put it into the list.
fittingMethods.add(candidate);
}
return fittingMethods;
}
Of course, if you do this often, you would not create the list of methods for every call, but only once, and reuse it then. (And if you only have a known interface with a low number of methods, use the switch statement instead, like others have recommended.)
You can place the various method names in an array structure.
Then choose a random index within the scope of the array.
Then use reflection to actually call the method using the randomly chosen name from the previous step
Why not make the following method:
public static void randomMethodFromFormInterface(Form form, String value) {
switch(random.nextInt(3) {
case 0:
form.setFirstName(value);
break;
case 1:
form.setLastName(value);
break;
case 2:
form.setGenderName(value);
break;
}
}
You can put it in a utility class. random here is, of course, an instance of java.util.Random.
Can I call these methods randomly on
an objet?
Yes, this is possible with Reflection. The randomness is not implemented in this example (I assume that you can easily do this with a random int) and all methods are called without knowing how they are named or how many methods are available. For simplicity the example assumes that the parameter is only a String (like in your example). Of course, you must instantiate a class which implements Form:
Class thisClass = Class.forName("FormImpl");
Object o = thisClass.newInstance();
Method[] methods = thisClass.getDeclaredMethods();
for(Method m : methods)
{
m.invoke(o, "test");
}
You could do something like below. However, I am not sure if I really like the idea of calling methods in an interface randomly. It breaks the contract in a way and sounds like a bad design idea in my opinion.
import java.util.Random;
public class RandomInterfaceImpl implements RandomInterface {
private Random rnd;
public RandomInterfaceImpl(){
rnd = new Random();
}
#Override
public void setFirstName(String value) {
System.out.println("called setFirstName");
}
#Override
public void setLastName(String value) {
System.out.println("called setLastName");
}
#Override
public void setGender(String value) {
System.out.println("called setGender");
}
#Override
public void getNextRandomMethod(String value) {
int nextRand = rnd.nextInt(3);
switch(nextRand){
case 0: setFirstName(value); break;
case 1: setLastName(value); break;
case 2: setGender(value); break;
}
}
}
public static void main(String[] args) {
RandomInterface myInterface = new RandomInterfaceImpl();
myInterface.getNextRandomMethod("Foo");
myInterface.getNextRandomMethod("Foo");
myInterface.getNextRandomMethod("Foo");
}
prints:-
called setFirstName
called setLastName
called setLastName

Categories