1

so I have a function which looks like this:

    public void addExceptionCommands(Class<? extends Throwable> exClass, Command... commands) {
        for (Command command : commands) {

            try {
                //Push the command to the stack of executed commands
                executedCommands.push(command);
                command.execute();

            } catch (CouldNotExecuteCommandException e) {
                // Default strategy is to rollback
                rollback();
                // Log
                e.printStackTrace();
                //I want to throw exClass here
            }
        }
    }

I want to throw exClass, how to achieve this? throw exClass does not work

EDIT: Thanks guys for all of the answers, I ended up with using a Supplier :D

Jakub Balicki
  • 180
  • 1
  • 11

4 Answers4

1

When you have a class type, you can do something like

throw exClass.newInstance(); 
user3487063
  • 3,672
  • 1
  • 17
  • 24
  • deprecated. https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance-- – LowKeyEnergy Nov 20 '19 at 16:56
  • 3
    It's safer to pass in a `Supplier extends Throwable>`, rather than the class. This guarantees that it can be constructed (checked at compile time), whereas the class approach relies on there being a zero-arg constructor (checked at runtime). – Andy Turner Nov 20 '19 at 16:56
1

You can only throw subclasses of Throwable and Class isnt.

However, you can modify your method to accept a supplier which generates a new Throwable which you then can throw:


    public <T extends Throwable> void addExceptionCommands(Supplier<T> exceptionSupplier, Command... commands) throws T {
        for (Command command : commands) {
            try {
                //Push the command to the stack of executed commands
                executedCommands.push(command);
                command.execute();
            } catch (CouldNotExecuteCommandException e) {
                // Default strategy is to rollback
                rollback();
                // Log
                e.printStackTrace();
                //I want to throw exClass here

                final T exception = exceptionSupplier.get();
                exception.addSuppressed(e);

                throw exception;
            }
        }
    }

You can then call your method like so:

addExceptionCommands(YourException::new, command1, command2, ...);
Felix
  • 2,256
  • 2
  • 15
  • 35
  • Here we're not so much suppressing the original exception as delivering it in an alternate form. It could make more sense to call `exception.initCause(e)` rather than `addSuppressed()`. – Andy Thomas Nov 20 '19 at 20:02
1

The parameter is a type of an exception. If you throw something, it has to be an instance of an exception.

I don't think this is going to work the way you think.

If you want the caller to define the type of exception thrown, then let the caller do so in its own code. A caller can catch the exception thrown by your method, and wrap it in any exception it chooses.

public void addExceptionCommands( Command... commands) 
throws CouldNotExecuteCommandException {
  ...
}

...
   try {
       commandable.addExceptionCommands( myCommands );
   } catch (CouldNotExecuteCommandException e) {
      // Wrap the command exception in my own.
      throw new MySpecialException( "My message", e );
   }

If you want to support a variety of exceptions from the commands, consider the example provided by Java's java.util.concurrent package. Consider ExecutorService.submit() methods, and the Future.get() method. The task submitted to the executor can throw a wide range of exceptions. But Future.get() wraps whatever exception was thrown in a single, well-defined, and declared ExecutableException.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
1

Try using java.lang.reflect.Constructor

Constructor.newInstance() is better than Class.newInstance() because it allows you to use arguments to create the new instance.

Constructor constructor = exClass.getDeclaredConstructor();
Throwable ex = (Throwable) constructor.newInstance(); 
throw ex;

With String argument (for message?)

Constructor constructor = exClass.getDeclaredConstructor(String.class);
Throwable ex = (Throwable) constructor.newInstance("message goes here"); 
throw ex;

https://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html

Also, Class.newInstance() has been deprecated. https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance--

LowKeyEnergy
  • 652
  • 4
  • 11