Why does Java StringReader throw an IOException?

Today I worked with the Java class StringReader , and I was very annoyed that it throws an IOException on the read method. I know that it extends the Reader class in which the read method throws an IOException, but I think that it is not needed for the StringReader. This class does not use external resources that may cause errors.

After a StringReader#read research, I found that StringReader#read throws an IOException if the string this class reads is null, but de facto this cannot happen , because if we try to pass a null value to the StringReader constructor throws an NPE.

What do you think of this, is it good practice to always throw the same exceptions as the superclass?


Edit: As U Mad Reader noted, this is not an interface, but a class.

+6
source share
3 answers

Please see StringReader # read () .

Look at the source code for the StringReader # read () method . It calls the ensureOpen() method, which actually throws an IOException , because ensureOpen() checks that the stream has not been closed.

If the reader is closed and then after read() is called again, what will happen?

Source code directly from the link (see comments):

 /** * Reads a single character. * * @return The character read, or -1 if the end of the stream has been * reached * * @exception IOException If an I/O error occurs */ public int read() throws IOException { synchronized (lock) { ensureOpen(); if (next >= length) return -1; return str.charAt(next++); } } /** Check to make sure that the stream has not been closed */ private void ensureOpen() throws IOException { if (str == null) throw new IOException("Stream closed"); } /** * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), * ready(), mark(), or reset() invocations will throw an IOException. * Closing a previously closed stream has no effect. */ public void close() { str = null; } 
+1
source

I think it's not a good practice to throw the same exceptions as defining a superclass or interface if your implementation ensures that this never happens. I would always reduce the signature to the minimum necessary.

IOException is required for all implementations you can imagine, including file sources, streams and sockets, etc. Without such implementations, they cannot report errors as a checked exception. But if the implementation does not need to throw a checked exception (which often causes annoyance to the calling code), removing it from the implementation class does no harm, but eliminates some of the load.

UPDATE:

I found the reason the read () method should throw an IOException : because of the contract defined for the close () method. From JavaDoc:

Closes a thread and frees up associated system resources. Once the thread is closed, calls to read (), ready (), mark (), or reset () will throw an IOException. Closing a previously closed stream is not affected.

+3
source

When you implement an interface method in your class, you are not required to provide the same exception arguments. The same case applies when you override a method declaration from a superclass.

 public class MyReader implements Readable { @Override public int read(CharBuffer cb) { return 0; } } 

But then you are not using the interface correctly. And it is not profitable for you if you code the interface.

 Readable readable = new MyReader(); try { readable.read(null); } catch (IOException e) { e.printStackTrace(); } 

Even in MyReader do not MyReader IOException , you still have to use a try block. Therefore, if you did not select an exception from the method that you are implementing, it may indicate that you missed something in your implementation of this method. Therefore, IMHO this is not a good practice.

The reason StringBuilder throws an IOException is not because it implements the Readable interface. The reason for this is to check the input in the ensureOpen() method, which throws an IOException when the input is null. Then the input can be null when the close() method is called or you pass null to the constructor. Since the close method is abstract, it should have some effect in the child class. It is expected that after you call, you will no longer be able to read it, and you will receive an IOException.

This is an ideal, clean and reliable implementation that takes into account all possible use cases.

+1
source

All Articles