Meaningless Drivel is fun!*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes interfaces and exceptions Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "interfaces and exceptions" Watch "interfaces and exceptions" New topic
Author

interfaces and exceptions

lev grevnin
Ranch Hand

Joined: Jan 23, 2003
Posts: 35
Guys, i have a question. This topic was discussed in some other threads, but something is always getting in my way of understanding what's going on. I will simplify the problem:
Given:
public interface I {
public void func();
}
public class A implements interface I {
public void func() throws IOException {
//implementations goes here
}
}
public class B implements interface I {
public void func() {
//implementations goes here
}
}
As you can see, both classes have the same behavior, but depending on implementation, one implementation throws an IOException and the other doesn't throw any exceptions. Of course, this code doesn't compile, because class A throws exception which is not declared in the overridden void func() from I. How can i solve this particular situation? (goal: I want to reuse the same interface for many classes which rightfully have this behavior, but depending on their implementation may or may not throw exceptions.) thanks in advance...
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Soapbox time.
A very useful way to understand inheritance (including interface inheritance, as in Java interfaces) is the substitution principle. One way to formulate it would be to say that wherever you have a program making use of an object of type I, you should be able to change the specific subtype it uses (say B) to any other subtype (say A) without changing the program. Although you can have very interesting discussions about how far you can or should take this, I find it to be a useful guiding light in OO design.
Java ensures that the substitution principle is satisfied at the language level. You just ran foul of that; if I defines a method, you cannot define a subtype A that throws extra exceptions, because a program written to use I would not anticipate such exceptions. You would not be able to use A in exactly the same way you would use B. There are extra exceptions to handle. We will come back to that in a moment.
One thing that is much less appreciated is that, while Java enforces the principle at the language level, you as a developer will have to ensure that it is satisfied at the semantical level. In other words, you have to ensure that func() means the same in all subtypes of I. This applies to the entire type ---your abstract type I will have an equally abstract meaning (semantics) which is given concrete shape (implemented) in all subtypes.
Let's give a more concrete, completely arbitrary example. Say you have a class B which has the method close(). You can use close() to indicate that you will no longer be using that instance of B. As B uses a file behind the scenes, B.close() closes the file. Now you extract the API of B into an interface I and make B implement I. Then you write a second, networked implementation A of I. A, too, uses a file behind the scenes, but that file is shared between each client that uses A.
What should A.close() do? Close the file? Of course not. That would amount to confusing semantics with implementation, and violate the substitution principle on the semantical level. Consider the meaning (semantics) of I.close(). It doesn't mean "close the file you're using". The interface I is wholly abstract -- implementations don't even necessarily use a file. I.close() means "I will no longer be using this instance of I, please release all resources I am holding". In the implementation B, that means closing the file. In the implementation A, it doesn't.
Back to the substitution principle.
The presence of IOexception in A suggests that it uses some communication channel with another process. On the other hand, the absence of IOException in I suggests that it is purely local. The fact that B doesn't compile is an expression of the fact that I is the interface for "a local func()". You cannot substitute a non-local implementation in it. Put differently, using the "IS-A" relationship for inheritance, a "remote func() implementation" IS-NOT-A "local func()".
So what to do about it? The easiest way is to look at the relationships you want to have. You want an interface I with a local implementation B and a remote implementation A. The meaning of I is then clearly "a func() which may be either local or remote". As "I" may be remote, it should clearly throw IOException.Any code that uses I will have to cater for IOExceptions, because such code needs to keep its options open on whether the implementation of I it gets is a local or remote one. Code which uses the local implementation only uses B directly and does not (and cannot) refer to I.
So what if you want to be able to have multiple local implementations, and want to write code that can work with any such implementation? Simple -- you need to introduce an extra interface L which is "a local func()".Any purely-local code can use L; any code that is agnostic about whether it gets a local or remote implementation can use I.
See also this thread.
Does that help?
- Peter
[ February 01, 2003: Message edited by: Peter den Haan ]
Arun Bommannavar
Ranch Hand

Joined: Jan 11, 2003
Posts: 53
Originally posted by lev grevnin:

Given:
public interface I {
public void func();
}
public class A implements interface I {
public void func() throws IOException {
//implementations goes here
}
}
public class B implements interface I {
public void func() {
//implementations goes here
}
}
As you can see, both classes have the same behavior, but depending on implementation, one implementation throws an IOException and the other doesn't throw any exceptions. Of course, this code doesn't compile, because class A throws exception which is not declared in the overridden void func() from I.

Peter has beautifully explained the problem and the solution.
As far I can see it, this is a case of "narrowing the scope" problem.
Lets say you have an concrete class A which defines a method "public void something(){ }".
Note that the access priviledge is "public". Now lets say there is another class B which extends A, and overrides the method. Can you now make it "private" or "protected"?. No.
Regards
Arun
 
jQuery in Action, 2nd edition
 
subject: interfaces and exceptions
 
Similar Threads
Never throw exception that SUN declares
Checked exception and interface.
RMI server interfaces
Exceptions.
Single Data Interface Justification