4

I have a set of string which I will be using as the Keys and for a particular string I want a function to be called. So is it possible to assign a function to the value in the pair?

exampleMap.get("SOME_STRING"); // should call a function abc();
Daanish
  • 1,061
  • 7
  • 18
  • 29
  • 1
    The only way this is possible is implementing your own map. The standard out of box Map implementation in java does not allow anything like this. – Santosh Jul 12 '13 at 07:50
  • No and yes, but not like you are trying. You'd have to use reflection and around about then you should be asking what has happened to your design – MadProgrammer Jul 12 '13 at 07:51
  • Why not use a strategy pattern and store it as the value in the hashmap. – Narendra Pathai Jul 12 '13 at 07:53

7 Answers7

7

Encapsulate your function in a Java interface:

public interface Task {
    void doSomething();
}

and then pouplate the map with instances of this interface:

map.put("someString", new Task() {
    @Override
    public void doSomething() {
        System.out.println("foo");
    }
});
map.put("someOtherString", new Task() {
    @Override
    public void doSomething() {
        System.out.println("bar");
    }
});

Then to call the function (task) associated with a given string s:

map.get(s).doSomething();
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • you beat me to it by 19 seconds! – vidit Jul 12 '13 at 07:53
  • But that only works if you can also control the code that uses the Map (because that has to call `doSomething` now, which it did not do before). – Thilo Jul 12 '13 at 07:56
  • Maybe I misunderstood the question. I answered to "is it possible to assign a function to the value in the pair". If the OP wants some function to be called each time `get()` is called, then it wouldn't be a Map anymore. – JB Nizet Jul 12 '13 at 08:35
  • How do I do this with a class that already exists? i don't want to make a new one, just execute an existing method. – markthegrea Mar 13 '19 at 14:46
3

No, java does not support any method objects yet. You could use reflection or try to replace your strings with enum constants and call the method on them.

morpheus05
  • 4,772
  • 2
  • 32
  • 47
2

Java doesn't support it directly, but you can do it indirectly using interfaces.

public interface Funct {
  public void apply();
}

and then when you want to use it as value, do something like..

Map<String, Funct> aMap = new HashMap<String, Funct>();
aMap.put("foo", new Funct() { public void apply() { System.out.println("bar"); } });
vidit
  • 6,293
  • 3
  • 32
  • 50
1

If you want this to be transparent to the user of the Map, you have to implement your own Map.

Thilo
  • 257,207
  • 101
  • 511
  • 656
1

Yes. Although, it's the java version of a "function": an anonymous class.

Best illustrated with an example:

interface MyFunction {
    public int calculate(int a, int b);
}

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

map.put("add", new MyFunction() {
    public int calculate(int a, int b) {
        return a + b;
    });

map.put("multiply", new MyFunction() {
    public int calculate(int a, int b) {
        return a * b;
    });

Patrick
  • 1,717
  • 7
  • 21
  • 28
Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

You may do it by using reflection. Consider the following code.

Map<String, Method> map = new HashMap<String, Method>();
SomeClass obj = new Someclass();
Method method = null;
try {
    method = obj.getClass().getMethod("someMethod", param1.class, param2.class, ...);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}   
map.put("someMethod", method);

try {
    (map.get("someMethod")).invoke(obj, arg1, arg2, ...);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}

The method to be called inside SomeClass

public class SomeClass    {
// Other class contents
    public void someMethod()    {
    // Target method contents
    }
}

A sample code using the above logic:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Temp3 {
    public static void main(String[] args) {
        Map<String, Method> map = new HashMap<String, Method>();
        Temp3 obj = new Temp3();
        Method method = null;
        try {
            method = obj.getClass().getMethod("someMethod");
        } catch (SecurityException e) {
        } catch (NoSuchMethodException e) {
        }

        map.put("someMethod", method);

        try {
            (map.get("someMethod")).invoke(obj);
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }
    }

    public void someMethod()    {
        System.out.println("**************************************");
    } 
}
Patrick
  • 1,717
  • 7
  • 21
  • 28
Dhrubajyoti Gogoi
  • 1,265
  • 10
  • 18
1

If you want that behavior you should define your own class.

The class should implement, at least, the following interface:

interface ApplicativeMap<K,V>{
  void put(K key, Function<V> producer);
  V get(K key);

where Function<V> should be an interface exposing the an V apply() method.

Your implementation should look something similar to this:

class ApplicativeMapImplementation implements ApplicativeMap{ private Map> functions;

 public void put(K key, Function<V> producer){
   functions.put(key, producer);
 }

 public V get(K key){
   if(functions.containsKey(key)){
     return functions.get(key).apply();
   } else{
     throw new NoSuchElementException();
   }
 }
mariosangiorgio
  • 5,520
  • 4
  • 32
  • 46