The java code:
public static <T extends Throwable> void checkNotNull(Object value, String name, Class<T> exceptionClass) throws T, SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
if (value==null)
throw ExceptionHelper.constructException(exceptionClass, name + " should not be null");
}
static <T extends Throwable> T constructException(java.lang.Class<T> exceptionClass, String message) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<T> constructor = exceptionClass.getConstructor(String.class);
T result = constructor.newInstance(message);
return result;
}
The junit code:
#Test
public void testCheckNotNull() {
try {
ValidationUtility.checkNotNull(null, "valuename", exceptionClass);
} catch (T e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Then the compiler says: Cannot use the type parameter T in a catch block
So how to solve this issue?
Since T is not known at compile time, you can't use it in a catch block like that. It is simply not something that is supported by the compiler, hence the error.
If your intent is to verify that the correct exception is thrown, I would suggest modifying your Test code like this:
#Test
public void testCheckNotNull() {
try {
ValidationUtility.checkNotNull(null, "valuename", exceptionClass);
} catch (Throwable e) {
assertEquals(exceptionClass, e.getClass());
}
}
By
Constructor<T> constructor = exceptionClass.getConstructor(String.class);
T result = constructor.newInstance(message);
You are creating result object of class passed as argument. Here by using 'T', only it means that you are constructing the result with the class which extends Throwable.
In the test method, even if do like this declare it:
#Test
public <T extends Throwable> void testCheckNotNull() {
try {
ValidationUtility.checkNotNull(null, "valuename", exceptionClass);
} catch (T e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Still T is a type, not a class e.g. Exception which can be caught. As you have found in the error, you will not be able to catch a Type.
Since you know, Type T is representing classes extending Throwable, use may want to use Throwable in the catch block.
} catch (Throwable e) {
As specified in earlier answer you cannot catch T. This is because of erasure. I would suggest using the JUnit4 expected if you are expecting an exception.
#Test(expected = Throwable.class)
public void testCheckNotNull() throws Throwable {
ValidationUtility.checkNotNull(null, "valuename", exceptionClass);
}
There is a bug with your test code too. If no exception is thrown then the test will still pass. You need to have a fail in there too
#Test
public void testCheckNotNull() {
try {
ValidationUtility.checkNotNull(null, "valuename", exceptionClass);
fail("expected to throw")
} catch (Throwable e) {}
}
Related
Is there any support for handling custom exception inside the Collectors.toMap.
I am calling a method inside the Collector.toMap which throws MyException. Can it be rethrown in the calling function pupulateValues()? For demonstration I used below code to rethrow MyException but couldn't get through. My objective is to handle MyException in main method.
public static void main(String[] args){
try {
pupulateValues();
} catch (MyException e) {
// do something
e.printStackTrace();
}
}
private static void pupulateValues() throws MyException{
Map<String,String> map = new HashMap<>();
map.put("asdf", "asdf");
map.put("ss", "fff");
map.put("aaaaaa", "aaaaaaa");
Map<String,String> map2=map.entrySet().stream().collect(
Collectors.toMap(entry->entry.getKey(),entry-> {
try {
return getCert(entry.getValue());
} catch (MyException e) {
// TODO Auto-generated catch block
throw new MyException();
}}));
}
static String getCert(String val) throws MyException {
if(val == null) {
throw new MyException("Some exception");
}
return val;
}
You have a few options:
make MyException an unchecked exception
wrap it: catch (MyException e) { throw new RuntimeException(e); }
trick the compiler:
https://stackoverflow.com/a/19757456/829571
https://stackoverflow.com/a/31470959/829571
https://github.com/jOOQ/jOOL#orgjooqlambdaunchecked
I have written a method which is returning some value in try statement. Inside catch I am calling handleException which will have conversion logic of understanding the exception and rethrowing new exception. Here handleException is always throwing exception, still the getXYZ() gives compile time error expecting return statement. I am not handling the exception, I am just throwing new exception so why does the method wants return statement.
public String getXYZ(String input) {
try {
return getFromDAO(input);
} catch (Exception e) {
handleException(e);
}
}
private void handleException(Exception e) {
try {
throw e;
} catch(SomeException se) {
throw new MyRuntimeException("MyException message", se);
} catch(SomeOtherException soe) {
throw new MyRuntimeException("MyException message", soe);
}
}
The other version of this method compiles.
public String getXYZ(String input) {
try {
return getFromDAO(input);
} catch (Exception e) {
throw e;
}
}
You are not throwing anything in the catch block, you're calling your handle function, which ultimately will result in a new exception being thrown, but the actual code in getXYZ is doing a function call in catch. What if you change handleException to later not throw an exception in some circumstances, what would getXYZ return then?
One way to solving this is making it clear to the compiler that you expect an exception to be thrown.
public String getXYZ(String input) {
try {
return getFromDAO(input);
} catch (Exception e) {
throw handleException(e); // compiles ok.
}
}
private RuntimeException handleException(Exception e) {
try {
throw e;
} catch(SomeException se) {
return new MyRuntimeException("MyException message", se);
} catch(SomeOtherException soe) {
return new MyRuntimeException("MyException message", soe);
} catch(RuntimeException re) {
return re;
} catch(Exception e2) {
return new MyRuntimeException("MyException message", e2);
}
}
BTW an alternative approach is to not wrap the Exception at all and leave the exception as it was.
public String getXYZ(String input) {
try {
return getFromDAO(input);
} catch (Exception e) {
throw rethrow(e); // compiles ok.
}
}
/**
* Cast a CheckedException as an unchecked one.
*
* #param throwable to cast
* #param <T> the type of the Throwable
* #return this method will never return a Throwable instance, it will just throw it.
* #throws T the throwable as an unchecked throwable
*/
#SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
throw (T) throwable; // rely on vacuous cast
}
You may want to consider using the new java 8 lambda features to solve your problem as well. You will have to create a functional interface to declare the signature of the lambdas (with the relevant exceptions). Your handleException method will now be the one who runs the lambda and handles the exceptions.
public String getXYZ(String input) {
return handleKnownExceptions(() -> getFromDAO(input));
}
private <T> T handleKnownExceptions(ThrowingCode<T> throwingCode)
{
try {
return throwingCode.get();
} catch(SomeException se) {
throw new MyRuntimeException("MyException message", se);
} catch(SomeOtherException soe) {
throw new MyRuntimeException("MyException message", soe);
}
}
#FunctionalInterface
public interface ThrowingCode<T>
{
T get() throws SomeException, SomeOtherException;
}
There is a pattern I have seen a few times to handle this situation. You let the handleException method declare that it returns an exception. This is only indicative though, it will never return anything, it will always throw, just as before. The declared return type will allow the caller to use a throw handleException() statement, which will keep the compiler happy. The resulting code will be:
public String getXYZ(String input) throws Exception {
try {
return getFromDAO(input);
} catch (Exception e) {
throw handleException(e);
}
}
/**
* This method will never return normally, always throws.
*/
private Exception handleException(Exception e) throws Exception
{
try {
throw e;
} catch(SomeException se) {
throw new MyRuntimeException("MyException message", se);
} catch(SomeOtherException soe) {
throw new MyRuntimeException("MyException message", soe);
}
}
I have a lambda expression, which can throw a IOException:
Function<String, List<String>> readFile = path-> {
try {
return Files.readAllLines(
Paths.get((String) path), Charset.forName("UTF-8"));
} catch (IOException e) {
return null;
}
};
I would like to write the same lambda expression without using the try {} catch {} block, so that the exception would be rethrown to the enclosing function:
public static void main(String[] args) throws IOException {
Function<String, List<String>> readFile = path-> {
try {
return Files.readAllLines(
Paths.get((String) path), Charset.forName("UTF-8"));
} catch (IOException e) {
return null;
}
};
}
The only problem is that I cannot define my own interfaces/classes and I can only use interfaces provided by Java APIs.
Would that be possible?
If you want to rethrow the excepion, you can use RuntimeException.
Add this to your catch body.
throw new RuntimeException(e);
Since Function.apply does not throw checked exceptions, you cannot do it ...
... in a legal way. However, you can consider "sneaky throw" if you can take the risk
interface FunctionX<T,R, X extends Exception> extends Function<T,R>
{
R applyX(T t) throws X;
#Override
default R apply(T t)
{
try
{
return applyX(t);
}
catch (Exception x)
{
throw Util.sneakyThrow(x);
}
}
public static <T,R,X extends Exception>
FunctionX<T,R,X> of(FunctionX<T,R,X> f){ return f; }
}
// Util.java
public static RuntimeException sneakyThrow(Throwable t)
{
throw Util.<RuntimeException>sneakyThrow0(t);
}
#SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T
{
throw (T)t;
}
Usage example
Function<String, List<String>> readFile = FunctionX.of( path-> {
return Files.readAllLines(
Paths.get(path), Charset.forName("UTF-8"));
} );
readFile.apply("/no-file");
public class TestException extends except2 {
public static void main(String[] args)throws Exception {
try {
try {
throw new TestException();
}
catch (final TestException e){
}
throw new except2();
}
catch (TestException a){
}
catch (Exception e){
throw e;
}
}
public TestException(){
}
}
class except2 extends Exception{
}
Hi all,
my JDK version is 8u45 which is latest one now.
I'm wondering that is "precise rethrow with a final exception" still working in SE 8?
As the code, if I take the "throws Exception" off it'll be compilation error, but it should be able to be ignored according to "precise rethrow with a final exception" function of SE7.
Another question is that we all know if there's an exception happened in the nested try box, we should still throw it out to outer catch box to avoid compilation error, I originally figured that we only need to throw an exception of any types & it'll do, so is my test result, I think it's to let compiler know that there's an exception in try box & catch box got it, too.
but if I alter it like the following code:
public class TestException extends except2 {
public static void main(String[] args)throws Exception {
try {
try {
throw new ArithmeticException();
} catch (final TestException e){
throw e;
}
} catch (TestException a){
} catch (Exception e){
throw e;
}
}
}
the (final TestException e) part will be compilation error with the message:
"the Exception "com.xxx.TestException" is never thrown in the corresponding try block",
and I'm confused because if nested catch block can't handle the exception, it shall goes to outer.
Then if I throw an ArithmeticException in the end of outer try block like this:
try {
try {
throw new TestException();
}
catch (final TestException e){
System.out.println("d");
}
throw new ArithmeticException();
}
catch (TestException a){
}
catch (Exception e){
throw e;
}
Same error to the outer catch box catch (TestException a){}
Why is that?
it should be caught by (Exception e) block.
If I can't throw different types of exception from the first exception of nested try block, why could I throw except2 in the first paragraph of code?
This is Oracles example for the feature, and it still works with Java 8:
static class FirstException extends Exception { }
static class SecondException extends Exception { }
public void rethrowException(String exceptionName)
throws FirstExceptio, SecondException // Since J7 no "Exception" needed
{
try {
if (exceptionName.equals("First")) {
throw new FirstException();
} else {
throw new SecondException();
}
} catch (Exception e) {
throw e; // effective final (i.e. not assigned)
}
}
This is described in the second half of this Oracle document. Your examples are all not really related to it. Especially not the one where you have a more specific and a general catch. This is explicitly mentioned in the document as not working.
Your first block would work if you use except2 (I renamed it to BaseException) which is the more specific one like this:
public class TestException extends BaseException {
public static void main(String[] args) {
try {
try {
throw new TestException();
}
catch (final BaseException e){
throw e; // this is defined as BaseEx, will fail on Java 6
}
}
catch (TestException a){ // this knows that no BaseEx is expected
}
}
public TestException(){
}
}
class BaseException extends Exception { }
As you can see, the main() method does not need to throw Exception anymore since the second catch block was sufficient.
Your first piece of code can be shortened to
class TestException extends except2 throws Exception {
public static void main(String[] args) {
try {
throw new except2(); // this
} catch (TestException a) {
} catch (Exception e) {
throw e;
}
}
public TestException() {
}
}
class except2 extends Exception {
}
You're throwing an except2. A TestException is an except2, but an except2 is not necessarily a TestException. The first catch block cannot handle the except2 exception. So the second one must. Since it further throws that exception, and that exception is necessarily checked, you need to have a throws clause.
Your second piece of code
class TestException extends except2 {
public static void main(String[] args) throws Exception {
try {
try {
throw new ArithmeticException();
} catch (final TestException e) { // nothing above throws a TestException
throw e;
}
} catch (TestException a) {
}
catch (Exception e) {
throw e;
}
}
}
Is trying to catch a TestException in the nested try block. But since TestException is a checked exception, the compiler can and does check if it can be thrown in that block. In your case, it can't. So it complains that's it useless to try and catch it.
Finally, in your last snippet
class TestException extends except2 {
public static void main(String[] args) throws Exception {
try {
try {
throw new TestException();
} catch (final TestException e) {
System.out.println("d");
}
throw new ArithmeticException();
} catch (TestException a) {
} catch (Exception e) {
throw e;
}
}
}
You're throwing and catching a TestException in the nested try-catch statement. So you can reduce the code to
class TestException extends except2 {
public static void main(String[] args) throws Exception {
try {
throw new ArithmeticException();
} catch (TestException a) {
} catch (Exception e) {
throw e;
}
}
}
Which has the same issue as your second piece of code. There is no code path there that can throw a TestException.
Regarding comments, and to simplify the second snippet, the error reduces to
class TestException extends except2 {
public static void main(String[] args) throws Exception {
try {
throw new ArithmeticException();
} catch (final TestException e) { // nothing above throws a TestException
throw e;
}
}
}
You have a catch(TestException) but nothing throws a TestException, so it's useless code which the compiler rejects.
From comments, this is the problem with your cases 2 and 3
// ignore everything around this
try {
// nothing in this block
// can throw a TestException
throw new ArithmeticException();
// this whole catch block is useless code
// Test Exception can never be thrown
} catch (final TestException e){
throw e;
}
// ignore everything around this
I have a Java 7 code, where I'm playing with MethodHanlde. The code is :
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
class HelloWorldApp {
public static void main(String[] args) {
MyMethodHandle obj = new MyMethodHandle();
obj.getToStringMH();
}
}
class MyMethodHandle {
public String getToStringMH() {
MethodHandle mh;
String s ;
MethodType mt = MethodType.methodType(String.class, char.class, char.class);
MethodHandles.Lookup lk = MethodHandles.lookup();
try {
mh = lk.findVirtual(String.class, "replace", mt);
} catch (NoSuchMethodException | IllegalAccessException mhx) {
throw (AssertionError)new AssertionError().initCause(mhx);
}
try {
s = (String) mh.invokeExact("daddy",'d','n');
}
catch(Exception e) {
throw (AssertionError)new AssertionError().initCause(e);
}
System.out.println(s);
return "works";
}
}
when I compile this :
javac HelloWorldApp.java
I get a error like this :
HelloWorldApp.java:23: error: unreported exception Throwable; must be caught or declared to be thrown
s = (String) mh.invokeExact("daddy",'d','n');
^
1 error
Where I'm making mistake?
As the Javadoc for MethodHandle.invokeExact states
public final Object invoke(Object... args) throws Throwable
This mean you mush catch or "throws" a Throwable
BTW As this throws a generic exception an alternative to
try {
s = (String) mh.invokeExact("daddy",'d','n');
} catch(Throwable t) {
throw new AssertionError(t);
}
is to rethrow the Throwable with
try {
s = (String) mh.invokeExact("daddy",'d','n');
} catch(Throwable t) {
Thread.currentThread().stop(t); // avoids wrapping the true exception
}
While using Thread.stop(t) can be unpredictable if you stop another thread. it is predictable if you throw it for the current thread.
Note: You need to ensure your method "throws" the appropriate checked exception for the method you are calling as the compiler cannot ensure this is the case.
invokeExact is declared throws Throwable. Thus, you need to catch Throwable instead of Exception. (An Exception is only one kind of Throwable.)
try {
s = (String) mh.invokeExact("daddy",'d','n');
}
catch(Throwable t) {
throw new AssertionError(t);
}