public void useSkill(Champion target, int skillIndex, boolean enemy) throws UtilitiesException {
if (champSkills[skillIndex].getManaCost() > this.currentMana) {
throw new RequirmentNotMetException("Not Enough mana");
}
I would like to throw a requirmentNotMetexception (which extends the utilitiesException) with message "not enough mana".
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unhandled exception type UtilitiesException
at eg.edu.guc.lol.game.champions.Tank.useSkill(Tank.java:27)
at eg.edu.guc.lol.game.champions.asfasf.main(asfasf.java:33)
I want to use exceptions to show the user that the champion has no mana instead of using an if/else statement checking the mana of the champion and printing not enough mana.
Somebody in the call stack has to handle the RequirmentNotMetException, or every method on the call stack has to declare that it throws the exception (or a parent), or the exception has to extend RuntimeException. Evidently, your main method is not declared as throwing it, and I wouldn't expect it to. So, check up the call chain, identify who should handle the exception, have that method handle it, and have everything in between declare itself as throwing it.
Your useSkill method looks fine. It declares the exception type in the throws clause of the method signature, so the problem is likely where this method is invoked. It looks to me like you're getting the error runtime, which might indicate that you have not recompiled all the classes using the Tank class after you have changed the signature. Still, you need to either catch the exception where you're using the useSkill method, or just pass it on by declaring those methods to throw that exception type as well.
Either you have not imported the UtilitieException or your UtilitiesException class has errors.
Related
I have a test that throws HttpException from a certain library (com.googlecode.jsonrpc4j). I have written a test like so:
Exception exception = assertThrows(HttpException.class,
() -> this.myApi.getInformation(date1, date2)
);
For this, I have imported the HttpException class like so:
import com.googlecode.jsonrpc4j.HttpException;
However, doing so gives me an error message:
'com.googlecode.jsonrpc4j.HttpException' is not public in 'com.googlecode.jsonrpc4j'.
Cannot be accessed from outside package
So, even though this exception is thrown in certain conditions, I am unable to test that this exception will be thrown under those conditions. Is there any way that I can test this?
My workaround, since the private HttpException extends RuntimeException, I can test it by asserting that RuntimeException is thrown. However, is there a better way to test this?
I agree with Andrew S. in the comments and your API shouldn't expose private exceptions:
Your code should probably not throw an exception defined in another library since that leaks the implementation to the caller and forces the caller to handle an exception that may change in the future. Instead, define your own exception, catch the dependent library exception, and throw your own exception. That should also help to simplify a unit test.
But if you really must and can not change your code, there is a workaround: asserting a general exception was thrown and then asserting the canonical name of this exception:
Exception exception = assertThrows(
RuntimeException.class,
() -> this.myApi.getInformation(date1, date2));
assertEquals(
"com.googlecode.jsonrpc4j.HttpException",
exception.getClass().getCanonicalName());
New Java programmers frequently encounter errors phrased like this:
"error: unreported exception <XXX>; must be caught or declared to be thrown"
where XXX is the name of some exception class.
Please explain:
What the compilation error message is saying,
the Java concepts behind this error, and
how to fix it.
First things first. This a compilation error not a exception. You should see it at compile time.
If you see it in a runtime exception message, that's probably because you are running some code with compilation errors in it. Go back and fix the compilation errors. Then find and set the setting in your IDE that prevents it generating ".class" files for source code with compilation errors. (Save yourself future pain.)
The short answer to the question is:
The error message is saying that the statement with this error is throwing (or propagating) a checked exception, and the exception (the XXX) is not being dealt with properly.
The solution is to deal with the exception by either:
catching and handling it with a try ... catch statement, or
declaring that the enclosing method or constructor throws it1.
1 - There are some edge-cases where you can't do that. Read the rest of the answer!
Checked versus unchecked exceptions
In Java, exceptions are represented by classes that descend from the java.lang.Throwable class. Exceptions are divided into two categories:
Checked exceptions are Throwable, and Exception and its subclasses, apart from RuntimeException and its subclasses.
Unchecked exceptions are all other exceptions; i.e. Error and its subclasses, and RuntimeException and its subclasses.
(In the above, "subclasses" includes by direct and indirect subclasses.)
The distinction between checked and unchecked exceptions is that checked exceptions must be "dealt with" within the enclosing method or constructor that they occur, but unchecked exceptions need not be dealt with.
(Q: How do you know if an exception is checked or not? A: Find the javadoc for the exception's class, and look at its parent classes.)
How do you deal with a (checked) exception
From the Java language perspective, there are two ways to deal with an exception that will "satisfy" the compiler:
You can catch the exception in a try ... catch statement. For example:
public void doThings() {
try {
// do some things
if (someFlag) {
throw new IOException("cannot read something");
}
// do more things
} catch (IOException ex) {
// deal with it <<<=== HERE
}
}
In the above, we put the statement that throws the (checked) IOException in the body of the try. Then we wrote a catch clause to catch the exception. (We could catch a superclass of IOException ... but in this case that would be Exception and catching Exception is a bad idea.)
You can declare that the enclosing method or constructor throws the exception
public void doThings() throws IOException {
// do some things
if (someFlag) {
throw new IOException("cannot read something");
}
// do more things
}
In the above we have declared that doThings() throws IOException. That means that any code that calls the doThings() method has to deal with the exception. In short, we are passing the problem of dealing with the exception to the caller.
Which of these things is the correct thing to do?
It depends on the context. However, a general principle is that you should deal with exceptions at a level in the code where you are able to deal with them appropriately. And that in turn depends on what the exception handling code is going to do (at HERE). Can it recover? Can it abandon the current request? Should it halt the application?
Solving the problem
To recap. The compilation error means that:
your code has thrown a checked exception, or called some method or constructor that throws the checked exception, and
it has not dealt with the exception by catching it or by declaring it as required by the Java language.
Your solution process should be:
Understand what the exception means, and why it could be thrown.
Based on 1, decide on the correct way to deal with it.
Based on 2, make the relevant changes to your code.
Example: throwing and catching in the same method
Consider the following example from this Q&A
public class Main {
static void t() throws IllegalAccessException {
try {
throw new IllegalAccessException("demo");
} catch (IllegalAccessException e){
System.out.println(e);
}
}
public static void main(String[] args){
t();
System.out.println("hello");
}
}
If you have been following what we have said so far, you will realise that the t() will give the "unreported exception" compilation error. In this case, the mistake is that t has been declared as throws IllegalAccessException. In fact the exception does not propagate, because it has been caught within the method that threw it.
The fix in this example will be to remove the throws IllegalAccessException.
The mini-lesson here is that throws IllegalAccessException is the method saying that the caller should expect the exception to propagate. It doesn't actually mean that it will propagate. And the flip-side is that if you don't expect the exception to propagate (e.g. because it wasn't thrown, or because it was caught and not rethrown) then the method's signature shouldn't say it is thrown!
Bad practice with exceptions
There are a couple of things that you should avoid doing:
Don't catch Exception (or Throwable) as a short cut for catching a list of exceptions. If you do that, you are liable catch things that you don't expect (like an unchecked NullPointerException) and then attempt to recover when you shouldn't.
Don't declare a method as throws Exception. That forces the called to deal with (potentially) any checked exception ... which is a nightmare.
Don't squash exceptions. For example
try {
...
} catch (NullPointerException ex) {
// It never happens ... ignoring this
}
If you squash exceptions, you are liable to make the runtime errors that triggered them much harder to diagnose. You are destroying the evidence.
Note: just believing that the exception never happens (per the comment) doesn't necessarily make it a fact.
Edge case: static initializers
There some situations where dealing with checked exceptions is a problem. One particular case is checked exceptions in static initializers. For example:
private static final FileInputStream input = new FileInputStream("foo.txt");
The FileInputStream is declared as throws FileNotFoundException ... which is a checked exception. But since the above is a field declaration, the syntax of the Java language, won't let us put the declaration inside a try ... catch. And there is no appropriate (enclosing) method or constructor ... because this code is run when the class is initialized.
One solution is to use a static block; for example:
private static final FileInputStream input;
static {
FileInputStream temp = null;
try {
temp = new FileInputStream("foo.txt");
} catch (FileNotFoundException ex) {
// log the error rather than squashing it
}
input = temp; // Note that we need a single point of assignment to 'input'
}
(There are better ways to handle the above scenario in practical code, but that's not the point of this example.)
Edge case: static blocks
As noted above, you can catch exceptions in static blocks. But what we didn't mention is that you must catch checked exceptions within the block. There is no enclosing context for a static block where checked exceptions could be caught.
Edge case: lambdas
A lambda expression (typically) should not throw an unchecked exception. This is not a restriction on lambdas per se. Rather it is a consequence of the function interface that is used for the argument where you are supplying the argument. Unless the function declares a checked exception, the lambda cannot throw one. For example:
List<Path> paths = ...
try {
paths.forEach(p -> Files.delete(p));
} catch (IOException ex) {
// log it ...
}
Even though we appear to have caught IOException, the compiler will complain that:
there is an uncaught exception in the lambda, AND
the catch is catching an exception that is never thrown!
In fact, the exception needs to be caught in the lambda itself:
List<Path> paths = ...
paths.forEach(p -> {
try {
Files.delete(p);
} catch (IOException ex) {
// log it ...
}
}
);
(The astute reader will notice that the two versions behave differently in the case that a delete throws an exception ...)
More Information
The Oracle Java Tutorial:
The catch or specify requirement
... also covers checked vs unchecked exceptions.
Catching and handling exceptions
Specifying the exceptions thrown by a method
This is a simplified class that describes my problem:
public class Main {
enum Test{
First(method()){ // Unhandled exception type Exception
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
}
Above someCondition depends on device and some situations and I can not decide in about it now, also as you can see, I do not want to catch Exception in method.
Yes. It is a compilation error.
No. There is no special syntax to deal with this.
I do not want to catch Exception in method.
Unfortunately if you throw a checked exception, it has to be caught further up the call stack. That is a fundamental design principal for the Java language, and one that the compiler enforces strictly.
In this, case there is no way to catch the checked exception. Hence, if you are going to call a method in enum constant parameter (as per your code), the method cannot throw a checked exception1.
Here is a possible workaround, though this is probably a bad idea:
public class Main {
enum Test{
First(methodCatchingException()){
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
static Object methodCatchingException() {
try {
return method();
} catch (Exception ex) {
throw new SomeRuntimeException("the sky is falling!", ex);
}
}
}
Another way to look at this problem is to ask yourself what should happen with the exception if the compiler let you write that ... and an exception was thrown? Where would it go?
You can't catch it ... because the enum initialization is like a static initialization.
If the Java runtime completely ignored the thrown exception, that would be really bad.
If the Java runtime crashed, then the model of checked exceptions is broken.
So, what this is saying to me is that the Java language design is right, the Java compiler is right ... and the real problem here is in your application design:
You should not be propagating a checked exception here. If an exception occurs in this context it is categorically NOT a recoverable error.
Maybe it is inadvisable to use an enum for this ... because of the potential for non-recoverable initialization errors.
(Note that if this method call terminates due to an unchecked exception, it will turn it into an ExceptionInInitializerError. In addition, the JVM will mark the enum class as uninitializable, and will throw an NoClassDefFoundError if your application attempts to use it; e.g. via Class.forName(...).)
I assume that Exception is used here for illustration purposes. It is a bad thing to declare methods as throws Exception or to throw new Exception(...)
1 - I had a look at the JLS for something to back this up. As far as I can tell, the spec does not mention this situation. I'd have expected to see it listed in JLS 11.2.3. However, it is clear that a compiler cannot allow a checked exception to propagate at that point as it would "break" the model of how checked exceptions work.
I don't think you want to be throwing a checked exception here (which is what Exception is). The reason: you're invoking the call of method inside of the constructor of Test. There's really not a clean way to deal with it.
While the obvious choice here is to switch to RuntimeException, I want you to reconsider throwing the exception in the first place. Since your enum will only ever have First declared in it, does it really make sense for it to throw an exception when it's being instantiated? Personally, I don't think it does; whatever dangerous operation it's doing should be deferred until you want to invoke it, and then would you want to throw your exception.
I have created my own UI component in Java. It has model and a few of model's methods can throw my exception called ModelException. I want to use this component in JRuby but I can't raise my ModelException:
raise ModelException # it cause TypeError: exception class/object expected
So I tried to create method throwing ModelException in Java and then invoke it in JRuby:
public class ScriptUtils {
private ScriptUtils() {
}
public static void throwModelException(ModelException e)
throws ModelException {
throw e;
}
}
but when I call throwModelException from JRuby I get:
org.jruby.exceptions.RaiseException: Native Exception: 'class app.ui.ModelException'; Message:
; StackTrace: app.ui.ModelException
...
Caused by: app.ui.ModelException
this native exception cannot be handled by Java code.
Any ideas how to throw Java exception in JRuby and catch it in Java?
This is a complete re-write of my original answer as I originally mis-read your question!
You can raise Java exceptions and catch them in JRuby but you need to be a bit careful how you call raise:
raise ModelException
Will cause a type error (as you saw) because to JRuby ModelException looks like a plain constant. Remember that in Ruby class names are constants. You can raise direct subclasses of Ruby Exception like this, e.g.:
raise RuntimeError
But I think such subclasses are a special case. Those that are actually Java classes you need to call with a constructor:
raise ModelException.new
Or whatever constructor/s you have for that class. An instance of ModelException, in JRuby, is a subclass of Exception because JRuby creates it as such, but the Java class itself isn't. All this is assuming that you have imported your ModelException class correctly.
As for your second example, I couldn't replicate that error at all. As long as I created the exception object correctly, as above, it worked and I didn't see any complaints about "Native Exception" at all. So I'm not sure what is happening there, sorry.
I am catching an Exception and trying to examine the getCause() of it, performing some further actions if the cause is a of type MyException, defined in another library.
I am getting this Eclipse (compiler?) error when trying to check if e.getCause() instanceof MyException:
Incompatible conditional operand types Throwable and MyException
When attempting to cast (MyException) e.getCause(), I get:
Cannot cast from Throwable to MyException
I can compiled e.getCause().getClass().equals(MyException.class), and this does return true.
The solution is that MyException inherited from an Exception in an external library, but the top-level project didn't include that external library. I discovered this when I created a private class that extended MyException, and got an inconsistent type hierarchy error.