views:

136

answers:

9

I have an ArrayList and wish to be able to call an index and use the returned string for a method call.

e.g.

stringList.get(2)();

Is there any way I could go about this?

+1  A: 

One would have to use reflection. See http://tutorials.jenkov.com/java-reflection/methods.html.

Paul Ruane
or a switch, if the amount of available options is known and sort of limited
David Hedlund
+11  A: 

So you want the returned String to be used as the name of the method to call?

You can do that using reflection, but I'd strongly discourage this.

Instead you will want to look into implementing a strategy pattern for example.

Joachim Sauer
A: 

Or maybe polymorphism and a factory method would be a better idea. You'd have to circumscribe the methods you'll be able to call, but that wouldn't be a bad idea.

If you want the full Monty, and you're using Java 6, maybe you can create a JavaScript function object and invoke it with Rhino.

duffymo
+1  A: 

Does the ArrayList have to contain Strings? Otherwise you could populate it with java.lang.reflect.Method instances, and call Method.invoke() on the returned instance.

Ton van Bart
A: 

Or if you insist on making the idea work regardless of any obstacles, you could call out to a dynamic language like JRuby or Clojure, both of which are willing to eval() a String.

Or Jython or Groovy or...

Carl Smotricz
+2  A: 

Yes, there is a way to use the returned string from the list for a method call.

As others users already pointed out, you need to use Reflection API. Can be complicated deal with that, depends on the particular scenario you are facing.

Just to show you the basic approach in a concrete but simplified example, I create this code. Copy it and play changing the index, and creating new methods with parameters after learn the basics of the API.

import java.lang.reflect.*;
import java.util.*;

public class DemoReflection {

    public static void main(String[] args) {

        List<String> myStringList = new ArrayList<String>();
        myStringList.add(0, "foo");
        myStringList.add(1, "printStr");
        myStringList.add(2, "otherMethod");
        myStringList.add(3, "stackoverflow");

        int index = 3;
        String methodName = myStringList.get(index);

        try {
            Class<?> c = Class.forName("DemoReflection");
            Object obj = c.newInstance();

            Method method = c.getDeclaredMethod(methodName, null);
            method.invoke(obj, null);

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

      }

    public void stackoverflow() {
         System.out.println("Stackoverflow rules!");
    }

    public void printStr() {
         System.out.println("Method printStr invoked...");
    }

}
JuanZe
This code is fragile and cannot be easily refactored (e.g. if you change the name of e.g. otherMethod()).
Thorbjørn Ravn Andersen
Yes, I'm aware of that. Is just to show a simplified way of doing what @Mac asked. I choose to answer his question and write a small sample of code so he can copy and run it immediately to learn more. Everyone is telling him (only based on "stringList.get(2)();") that he shouldn't use that approach and suggesting patterns and plenty of options to redesign his solution. The fact is we don't know the context of his problem, and only a few of us answered his simple question: "Is there any way I can use the returned string from a list for a method call?"
JuanZe
A: 

In Java - no way. That's not a Java language feature. Your're hoping for something like

// NOT VALID JAVA
String myColoring = paintBlackOrWhite() ? "black" : "white";
myColoring(myBathroomWall);
// NOT VALID JAVA

Like others suggested, a pure technical solution would be using reflections: take the result string, find the corresponding method and invoke it. A technical solution could even be a map like

Map<String, java.lang.reflect.Method> myMethods;

and do something like

get("black").invoke(myObject, myParams);

but all of that is nice to know and you shouldn't use it unless forced or you have a concrete problem where even SO doesn't have a solution ;)

Andreas_D
+1  A: 

If I understand your needs here is an example based on an interface ; the list then contains implementations of the interface rather than method names:

import java.util.ArrayList;
import java.util.List;

public class Test {

public static void main(String[] args) throws Exception {

    List<Action> actions = new ArrayList<Action>();
    actions.add(new Action(){
        public void execute() {
            System.out.println("Action 0");
        }});
    actions.add(new Action(){
        public void execute() {
            System.out.println("Action 1");
        }});

    actions.get(0).execute();
    actions.get(1).execute();

}


static interface Action{ 
    void execute(); 
}

}

pgras
A: 

First of call you can't call a method in java without an object to call it on. Is that in the list also.

It would be better to have a list of Runnable...

List<Runnable> runnables = ...
runnables.get(2).call();

If you have the object you need to call, and you want to use reflection (can be slow) then commons-beans can help make it simple. See http://commons.apache.org/beanutils

import org.apache.commons.beanutils.MethodUtils;

Object target = ...
List<String> methodNames = ...
MethodUtils.invokeMethod(target, methodNames.get(2), /*args*/ null);

To give better I'd advice I'd need to know more about the problem you are trying to solve.

David Roussel