4

I want to store methods pointer in map to execute them based on a string value. Аrom what I found, I can use Map<String, Runnable> to do it, but the problem is I want to get the return value from the method.

Say I have something like this:

private Map<String, Runnable> timeUnitsMap = new HashMap<String, Runnable>() {{
    timeUnitsMap.put("minutes", () -> config.getMinutesValues());
}}

The method config.getMinutesValues() is from another class.

How can I do int value = timeUnitsMap.get("minutes").run(); or to store something else in the map (instead of Runnable) in order to get the value from the function in the map?

Ofek Agmon
  • 5,040
  • 14
  • 57
  • 101
  • 1
    Instead of `() -> config.getMinutesValues()`, did you know you can write `config::getMinutesValues`? – Sam Dec 18 '16 at 08:29

3 Answers3

11

Runnable doesn't return a value. You should use Supplier or Callable instead.

The primary difference between Supplier and Callable is that Callable allows you to throw a checked exception. You then have to handle the possibility of that exception everywhere you use the Callable. Supplier is probably simpler for your use case.

You would need to change your Map<String, Runnable> to a Map<String, Supplier<Integer>>. The lambda function itself wouldn't need changing.

@assylias pointed out in a comment that you could also use Map<String, IntSupplier>. Using an IntSupplier avoids boxing your int as an Integer.

Sam
  • 8,330
  • 2
  • 26
  • 51
  • 1
    Or more likely an `IntSupplier` in this specific case. – assylias Dec 18 '16 at 08:31
  • 1
    @assylias great idea! That wouldn't have occurred to me. – Sam Dec 18 '16 at 08:32
  • thanks for your answer. I do have another question, edited the original one. would appreciate your answer. – Ofek Agmon Dec 18 '16 at 08:49
  • 2
    @OfekAgmon please cancel your edit, and ask another, separate question. Your original question has been answered. – JB Nizet Dec 18 '16 at 08:51
  • 1
    Agreed; one question per post keeps the site organised. Feel free to post another separate question though, I'm happy to take a look. – Sam Dec 18 '16 at 08:58
0

Use Callable instead of Runnable.

Dave
  • 4,282
  • 2
  • 19
  • 24
0

You will need to use Callable instead of Runnable and also, you would need to override call() method.

You can get a clue from following snippet:

private Map<String, Callable<Integer>> timeUnitsMap = new HashMap<String, Callable<Integer>>(){
        {timeUnitsMap.put("minutes", () -> call());}};

and you would need to override call() method as well,

@Override
    public Integer call() throws Exception {
        return 1;
}