pragmatrick
pragmatrick

Reputation: 645

Mapping functions to elements of array

I am have a general question about mapping things in java. I am not quite stuck, but I feel that my approach is not really beautiful and could cause problems if one would imagine my small private project will become bigger.

Imagine I have an array = {1, 2, 3, 4}, it does not have to be numbers, just any sign in general. Then I get an input from a user, which can only be part of an array (no invalid inputs possible). Now depends on which element they choose, a specific function will be executed. The only thing I came up with is:

switch (input) {
   case array[0]:
      doOneThing();
      break;
   case array[1]:
      doAnotherThing();
     break;
   case array[2]:
      doAThirdThing();
      break;
   case array[3]:
      doSomethingElse();
       break;
}

This method works, but is not beautiful to expand. I take every possible idea with great thanks.

Upvotes: 1

Views: 88

Answers (3)

WJS
WJS

Reputation: 40062

You must have constants in your switch statement so what you specified won't work. You could do something like this though as an example. You're not limited to using Runnable lambdas. Any functional Interface could be used and the appropriate arguments supplied when called.

Note that it is not a good idea to allow any method of any class to be invoked as it could lead to unexpected results or security issues depending on how it is to be used.

public class ThisClass {
    
    public static void main(String[] args) {
        Map<String, Runnable> map = new HashMap<>();
        ThisClass tc = new ThisClass();
        
        map.put("A", () -> tc.doOneThing());
        map.put("B", () -> tc.doAnotherThing());
        map.put("C", () -> tc.doAthirdThing());
        map.put("D", () -> tc.doSomethingElse());
        
        for (String str : new String[] { "A", "B", "Q", "C", "D", "E" }) {
            map.getOrDefault(str, () -> tc.defaultMethod()).run();
        }
    }
    
    public void doOneThing() {
        System.out.println("Doing one thing");
    }
    
    public void defaultMethod() {
        System.out.println("Executing default");
    }
    
    public void doAnotherThing() {
        System.out.println("Doing Another thing");
    }
    
    public void doAthirdThing() {
        System.out.println("Doing a third thing");
    }
    
    public void doSomethingElse() {
        System.out.println("Doing something Else");
    }
}

Prints

Doing one thing
Doing Another thing
Executing default
Doing a third thing
Doing something Else
Executing default

You can also do something like this.

Map<String, DoubleBinaryOperator> map = new HashMap<>();

map.put("+", (a, b) -> a + b);
map.put("-", (a, b) -> a - b);
map.put("*", (a, b) -> a * b);
map.put("/", (a, b) -> a / b);

DoubleBinaryOperator error = (a, b) -> {
    throw new IllegalArgumentException();
};

for (String str : new String[] { "+", "-", "L", "/", "*" }) {
    try {
        double result = map.getOrDefault(str, error)
                .applyAsDouble(2.0, 3.0);
        System.out.println("result = " + result);
    } catch (IllegalArgumentException iae) {
        System.out.println("unknown operator \"" + str + "\"");
    }
}

Prints

result = 5.0
result = -1.0
unknown operator "L"
result = 0.6666666666666666
result = 6.0

Upvotes: 1

batman567
batman567

Reputation: 899

Sounds like you want to look at Java Reflection Api.

Class c=Class.forName("xxxx")

where {xxxx} is a string you have constructed from parameters.

you can similarly invoke method names.

Note - beautiful code often comes at some cost - be it readability, performance or security (esp in the case of reflection). Personally i don't mind a long switch statement - it might not be pretty but it will never bite you.

Upvotes: 0

fooiey
fooiey

Reputation: 1550

One possible way is if you can create a name of a function using their inputted value. For example, if they input 1, you will call "function1" or if you input 2, you call "function2". Then you can use reflection to call the method by it's string name.

Something like this.

Upvotes: 0

Related Questions