1

I'm looking for a way to call any given method in my class without having to do the whole try-catch statement.

EXAMPLE:

public void Worker(String handle) throws Exception
{
    if(PROTOCOL.contains(handle)) 
    {
        System.out.println("good");
        Worker.handle;
    }
    else { 
            throw new Exception("Don't understand <" + handle + ">");
         }
}

PROTOCOL is a list of allowed commands.

I know I can say if(input = ....){do....} but I want to be able to do the above; call my class with the input value.

Is this possible?

5
  • 1
    Have a look at Reflection: docs.oracle.com/javase/tutorial/reflect/member/… Commented Sep 6, 2018 at 15:41
  • Throwing generic Exception is a design problem. Consider throwing an unchecked exception - IllegalStateException seems reasonable for the posted code. If handle could be changed to an enum then the only problem would be if it's null. Commented Sep 6, 2018 at 15:49
  • haha yeah I thought that it was to general. Ill change it to IllegalStateException for sure Commented Sep 6, 2018 at 16:03
  • 1
    IllegalArgumentException will be better here as handle is passed as argument Commented Sep 6, 2018 at 16:08
  • What would the difference be with state and argument? I get the obvious implication, but ist state more general vs argument is like inputting int when requiring a string? Commented Sep 6, 2018 at 16:19

3 Answers 3

1

Depending on what your commands would look like you could use a Map<String, Command> which you'd then use like this:

Map<String, Command> PROTOCOL = ... //you build that map somehow

Command c = PROTOCOL.get(handle);
if( c != null ) {
    System.out.println("good");
    c.execute();
} else { 
    throw new Exception("Don't understand <" + handle + ">");
}

Command could then be a class or function interface:

interface Command {
  void execute();
}

Used as a class interface

class MyCommand implements Command {
  //this can have private data

  void execute() {
    //do whatever is needed
  }
}

PROTOCOL.put("mycommand", new MyCommand(/*you could pass parameters here*/));

Advantages:

  • The interface can have more than 1 method, e.g. it could have a String getName() as well.
  • Commands can have parameters, e.g. you could provide one implementation and use different names that are bound to the same command with different parameters (e.g. a "increment" and "decrement" could be bound to AddCommand(1) and AddCommand(-1)).
  • You could use some dependency inversion mechanism (e.g. via CDI) to have commands register themselves to PROTOCOL. That way you could even add commands via some plugin mechanism.
  • Using interfaces for classes might be easier to grasp for others.
  • Easier to structure for larger commands as you can easily extract the classes into separate files.

Used as a function interface (e.g. via lambdas)

PROTOCOL.put("mycommand", () -> { 
  //do whatever is needed
});

Advantages:

  • No classes needed which can be more concise for short commands.
Sign up to request clarification or add additional context in comments.

8 Comments

So you're saying that I should make my protocol list a hashmap with two prarams, (name, method) then I can call it that way or make an interface.
@1nn15 As far as I understand your question (which is quite short) your protocol would basically consist of a list of "keywords" that are mapped to some code. Thus using a map (which could be a hashmap) seems to be a good fit. You'd need the interface as well (i.e. not "or" but "and") as the map's value type.
ahh ok, I get that.
I guess trying to be lazy only makes things more complicated XD
Command interface is unnecessary here, you can use Runnable or Callable
|
0

If you do not want to use try-catch (handle exceptions yourself) then declare those exceptions on the calling method followed after throws keyword.

https://docs.oracle.com/javase/tutorial/essential/exceptions/declaring.html

Basically you are delegating the exception handling to the caller of your method.

Comments

0

Here is a simple working example showing some things that you can do using reflection.

Note: I decided to store available methods in a list, but this could be easily modified to use a predefined list of Strings. I also threw an unchecked IllegalArgumentException from the worker method.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Worker {

    public void method1() {
        System.out.println("method1 called");
    }

    public void method2() {
        System.out.println("method2 called");
    }

    public void worker(String handle) throws IllegalArgumentException {
        Class<? extends Worker> clazz = this.getClass();
        List<Method> methods = Arrays.asList(clazz.getMethods());

        if (methods.stream().map(m -> m.getName()).collect(Collectors.toList()).contains(handle)) {
            try {
                Method method = clazz.getDeclaredMethod(handle);
                method.invoke(this);
            } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            throw new IllegalArgumentException("Don't understand <" + handle + ">");
        }
    }

    public static void main(String[] args) {
        new Worker().worker("method1");
        new Worker().worker("method2");
        new Worker().worker("method3");
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.