Consider the following code:
public interface I1 {
public void bar1() throws IOException;
}
public interface I2 extends I1 {
public void bar2() throws Exception;
}
public interface I3 {
public void bar3() throws Exception;
}
public abstract class A implements I2 {
public void bar2() throws Exception{};
public void bar3() throws Exception{};
protected abstract void bar4();
protected void bar5() {};
}
Now, I created a class, B as follows:
public class B extends A implements I3 {
#Override
protected void bar4() {}
public void bar1() {}
}
Why is the compiler letting me do that? I mean, shouldn't it be:
public void bar1() throws IOException;
When overriding you cannot throw Broader or newer exception. Not throwing a super class method's exception is allowed.
The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime exception unless it's a subclass of FileNotFoundException.
Inheritance lets you make functions more specific.
You can reduce the number of things you throw, you can return a subtype of the return type, you can accept a supertype of a parameter type.
This is because any possible call to your method most be a legal call to the super method, but the reverse does not need to be true.
In other words in your example:
new B().bar1()
You know it doesn't throw the exception, you don't need to catch.
((A)new B()).bar1()
You need to catch the exception as since you are now processing any A or subclass of A you might need to handle it.
If you tried to do the reverse though and create a class C:
public class C extends A implements I3 {
#Override
protected void bar4() {}
public void bar1() throws IOException, SomeOtherException {}
}
This would not be allowed as now if you tried to use a C as an A you are not going to be catching SomeOtherException.
Related
I am looking for an elegant way to create a factory for dependency injection. In my case, the factory simply has to call a one-argument constructor. I found this answer outlining how to use a Function<ParamType, ClassToNew> for such purposes.
But my problem is: in my case, my ctor declares to throw some checked exception.
What I don't get: creating that Function using a method reference to that constructor doesn't work. As in:
import java.util.function.Function;
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
Function<String, Mcve> mcveFactory = Mcve::new;
}
}
tells me about "Unhandled exception: java.lang.Exception" for Mcve::new. Although this code is not invoking the constructor.
Two questions:
why that error? The above code does not invoke the ctor (yet)?
are there any elegant ways to solve this puzzle? ( simply adding throws Exception to my main() does not help )
You need to provide a custom interface ThrowingFunction which has one method that throws Exception.
public interface ThrowingFunction<ParameterType, ReturnType> {
ReturnType invoke(ParameterType p) throws Exception;
}
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
ThrowingFunction<String, Mcve> mcveFactory = Mcve::new;
}
}
Using this approach results in calling mcveFactory.invoke("lalala"); forcing you to handle the exception thrown by the constructor.
Reason for the error is that the actual function reference you want to store (not 100% sure about the terminology) throws an exception and therefore the types simply do not match up. If you could store Mcve::new inside a function then whoever calls the function no longer knows an Exception can be thrown. What would then happen if the exception would actually be thrown? Both throwing the exception and discarding it do not work.
Alternative: if you need to actually retrieve a Function<String, Mcve> in the end then you need to write a function (or lambda) that invokes the constructor, catches the exception and either discards it or rethrows it wrapped inside a unchecked RuntimeException.
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
Function<String, Mcve> mcveFactory = parameter -> {
try {
return new Mcve(parameter);
} catch (Exception e) {
throw new RuntimeException(e); // or ignore
}
};
}
}
I would argue that the error message itself is at least a bit misleading since you normally see it when actually invoking the method. I can certainly understand the confusion resulting in the first sub-question. It would be clearer (sadly not possible) to state something like
Incompatible types Function<String,Mcve> vs. Function<String,Mcve> throws Exception.
I had to do that just recently... If you can change the class definition, you could use the infamous sneaky throws way of doing things:
static class OneArg {
private final String some;
#SuppressWarnings("unchecked")
public <E extends Exception> OneArg(String some) throws E {
try {
this.some = some;
// something that might throw an Exception...
} catch (Exception e) {
throw (E) e;
}
}
public String getSome() {
return some;
}
}
Function<String, OneArg> mcveFactory = OneArg::new;
I've been thinking about this for a while and indeed - if you want to have a Function that declares clearly your intention, I think that you need to have a Function that would extend the java.util.Function, something like this:
#FunctionalInterface
public interface ThrowingFunction<T, R> extends Function<T, R> {
R applyWithExc(T t) throws Exception;
#Override
default R apply(T t) {
try {
return applyWithExc(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
You can btw choose which method you call when you define your constructor reference - the one that would throw an Exception and one that would silently wrap it with a RuntimeException.
I have two classes inheriting from java.lang.Exception. They both have a method with the same signature void a(){...}. They both can be thrown in a code block. If I do:
catch (SubException1 | SubException2 e)
{
e.a();
}
Then it won't compile because method a() does not belong to Exception. Is it a Java language flaw? How should I design my code properly to prevent code redundancy?
When you catch multiple exception types in a single catch statement the inferred type of the caught exception is the greatest common denominator of those classes. In your case, the greatest common denominator is Exception, which doesn't have the method void a(). In order to make it accessible to the catch block you could either extract it to a common base class, or (arguably) more elegantly, define it in an interface that both classes implement:
public interface SomeExceptionInterface {
void a();
}
public class SomeException extends Exception implements SomeExceptionInterface {
// Implementation...
}
public class SomeException2 extends Exception implements SomeExceptionInterface {
// Implementation...
}
If you need to access a method called a(), you need a type that provides that method. A simple solution could be:
public class AbstractSubException extends Exception {
public abstract void a();
}
public class SubException1 extends AbstractSubException {
#Override public void a() { ... }
}
public class SubException2 extends AbstractSubException {
#Override public void a() { ... }
}
Then you can catch the way you did or (somewhat simpler):
catch (AbstractSubException e) {
e.a();
}
Maybe the code for the method a is the same in all sub classes. Then you can make it concrete and put the code into the parent class.
I have the following example:
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>();
a.m(); //Exception here!
}
public static class AbstractErrorHandler {
public static void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public static void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(){
T.handle();
}
}
}
IDEONE
Why the method of the base class is called, but not of the derived? The signatures of the handle() methods are perfectly the same. I know that static methods don't inherit, but shouldn't a compile-time error be thrown in my case then?
Could someone explain that behavior?
The reason for this is that the compiler doesn't know which exact subtype of AbstractErrorHandler will be replacing T at Runtime. That's why it just binds the method call T.handle() to the AbstractErrorHandler.handle() method.
The problem here is that you're mixing inheritance with the static features of the classes in Java.
In order to have this working (correctly), you have to get rid of the static modifier for the .handle() methods and keep an instance of T in the A class. This T instance (at Runtime) will be some specific subclass of AbstractErrorHandler and then the actual .handle() method will be executed.
For example:
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>(new ConcreteErrorHandler());
a.m();
}
public static class AbstractErrorHandler {
public void handle() {
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler {
public void handle() {
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler> {
T instance;
A(T instance) {
this.instance = instance;
}
public void m() {
instance.handle();
}
}
}
4.4. Type Variables tells us that:
The members of a type variable X with bound T & I1 & ... & In are the members of the intersection type T & I1 & ... & In appearing at the point where the type variable is declared.
Therefore the members of T extends AbstractErrorHandler are the members of AbstractErrorHandler. T.handle(); refers to AbstractErrorHandler.handle();.
The erasure of a bounded type parameter is the bound (and in the case of a bound intersection, the first type in the bound). So in your case, T extends AbstractErrorHandler is erased to AbstractErrorHandler and your method is effectively replaced by:
public void m() { AbstractErrorHandler.handle(); }
See for example JLS 4.6
The erasure of a type variable (§4.4) is the erasure of its leftmost bound.
Because basically your method m will be compiled into
public void m(){
AbstractErrorHandler.handle();
}
I believe it is because static is class scoped and you are telling the compiler to use AbstractErrorHandler implicitly by using T extends AbstractErrorHandler.
The runtime will assume the highest class level since type erasure occurs at runtime.
The implementation of m only uses T which is an AbstractErrorHandler, despite the fact you declared it to be the concrete type in the main method, which is not in the scope of the m method.
Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime. Therefore upper bound type AbstractErrorHandler is used.
see for more details: https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html
The reason is because you are using generics and java static methods that are hidden not overriden. At compile time the only know information is the AbstractErrorHandler class (generics works at a compile time in java, there is no bytecode with generics information) and the method called is the one of the class.
If you change the method handle form static to "instance" the implementation called is the "right" one (because the method is overridden not hidden )as in the example below .
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<AbstractErrorHandler> a = new A<AbstractErrorHandler>();
a.m(new ConcreteErrorHandler()); //Exception here!
}
public static class AbstractErrorHandler {
public void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(T t){
t.handle();
}
}
}
First let me apologize for the terrible title, but I had no idea how to summarize this in a single sentence.
public class GenericFun {
public class TypedStream<I extends OutputStream> {
I input;
public I getInput() { return input; }
public void setInput(I input) { this.input = input; }
}
public abstract class GarbageWriter<I extends OutputStream> {
public void writeGarbage(I output) throws Exception {
output.write("Garbage".getBytes());
}
}
public class GarbageWriterExecutor<I extends OutputStream> extends GarbageWriter<I> {
public void writeTrash(TypedStream stream) throws Exception{
this.writeGarbage(stream.getInput()); // Error
this.writeGarbage((I)stream.getInput()); // OK
}
}
}
In the above code (the OutputStream is just an example) in class GarbageWriterExecutor class in the method first line causes compilation error, while the second one don't. I have two questions regarding this.
Why stream.getInput() causes error, even though TypedStream.I is known to extend OutputStream?
How can I solve this issue without the ugly casting?
Because your method
public void writeTrash(TypedStream stream)
should also make sure TypedStream type is defined, like this :
public void writeTrash(TypedStream<I> stream)
Edit : Thomas answer actually explain why
TypedStream stream will disable generic type checking and thus the compiler only knows that getInput() will return an object, hence the error.
TypedStream stream will disable generic type checking and thus the compiler only knows that getInput() will return an object, hence the error.
Try writeTrash(TypedStream<I> stream) instead.
Maybe you event want to use writeTrash(TypedStream<? extends I> stream) in order to be able to pass any TypedStream which is parameterized for I or subclasses of I.
Yet another alternative would be
public class GarbageWriterExecutor extends GarbageWriter<OutputStream> {
public void writeTrash(TypedStream<?> stream) throws Exception{
this.writeGarbage(stream.getInput());
}
}
or
public class GarbageWriterExecutor extends GarbageWriter<OutputStream> {
public void writeTrash(TypedStream<? extends OutputStream> stream) throws Exception{
this.writeGarbage(stream.getInput());
}
}
Simply use:
public class GarbageWriterExecutor<I extends OutputStream> extends GarbageWriter<I> {
public void writeTrash(TypedStream<I> stream) throws Exception {
this.writeGarbage(stream.getInput());
}
}
I.e. parameterize your TypedStream parameter with I.
1.Resolve this by using this code.
public void writeTrash(TypedStream<I> stream) throws Exception{
this.writeGarbage(stream.getInput());
this.writeGarbage(stream.getInput());
}
2. In Generic class class name is followed by a type parameter section. If you are not doing this then you have to do casting.
I read this code where the interface throws an exception, but the class which implements it doesn't throw one or catch one, why is that? Is it legal or safe in java?
import java.rmi.*;
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
public String sayHello() {
return "Server says, 'Hey'";
}
public MyRemoteImpl() throws RemoteException {}
public static void main (String[] args) {
try {
MyRemote service = new MyRemoteImpl();
Naming.rebind("RemoteHello", service);
} catch(Exception ex)
{
ex.printStackTrace();
}
}
}
A general rule of implementing and extending is you can make your new class or interface "less restrictive" but not "more restrictive". If you think of the requirement to handle an exception as a restriction, an implementation that doesn't declare the exception is less restrictive. Anybody who codes to the interface will not have trouble with your class.
— Stan James
As part of the discussion at http://www.coderanch.com/t/399874/java/java/Methods-throwing-Exception-Interface
If a Java method overrides another in a parent class, or implements a method defined in an interface, it may not throw additional checked exceptions, but it may throw fewer.
public class A {
public void thrower() throws SQLException {...}
}
public class B extends A {
#Override
public void thrower() throws SQLException, RuntimeException, NamingException {...}
}
SQLException is fine; it's declared in the overridden method. It could even be replaced by a subclass like SerialException.
RuntimeException is fine; those can be used anywhere.
NamingException is illegal. It isn't a RuntimeException, and isn't in A's list, even as a subtype.
Great answer by #Chetter Hummin.
One way to look at this, and I find it easy to remember, is interface's implementations can be more specific but not more general.
For example in interface void test() throws Exception means "test may throw exception"
then implementation can be void test() means "test will not throw exception" (more specific)
or implementation can be void test() throws NullpointerException (more specific)
interface x {
void testException() throws Exception;
}
public class ExceptionTest implements x {
#Override
public void testException() { //this is fine
}
////// or
#Override
public void testException() throws NullPointerException { // this is fine
}
}