12

Since ByteArrayOutputStream simply writes to memory, an IOException should never occur. However, because of the contract of the OutputStream interface, all stream operations define IOException in their throws clause.

What is the correct way to "handle" this never-occurring IOException? Simply wrap operations in an empty try-catch block?

Or are there any actual situations where ByteArrayOutputStream could throw an exception?

(See also: How can I handle an IOException which I know can never be thrown, in a safe and readable manner?)

EDIT

As Jon points out, ByteArrayOutputStream doesn't declare a throws clause on the write methods it defines -- however, it inherits write(byte[]) from OutputStream, and that one does throw IOEXception (quite odd that BAOS wouldn't override this method, as it could replace the superclass version -- which writes one byte at a time -- with a far more efficient arraycopy call)

Community
  • 1
  • 1
Tony the Pony
  • 40,327
  • 71
  • 187
  • 281

6 Answers6

12

Well, ByteArrayOutputStream doesn't declare that any of its methods throw IOException except writeTo and close. (I don't know why close still declares it, to be honest.)

If you've got a reference of type OutputStream though, you would still see the throws declarations from that, of course.

I wouldn't use an empty catch block - I'd throw something like IllegalStateException or a similar unchecked exception: it means you're in a situation you really don't expect, and something's gone badly wrong.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • the IOException on `close()` must be a mistake - especially when the javadoc says it "has no effect" – irreputable Jun 07 '11 at 21:50
  • 1
    +1 Thanks! I just noticed that `ByteArrayOutputStream.write` doesn't in fact declare `IOException` -- but Eclipse complains about an unhandled exception whenever I use it... strange. – Tony the Pony Jun 07 '11 at 21:52
  • @Jen: Are you sure you're calling methods on a variable *declared* as `ByteArrayOutputStream`? – Jon Skeet Jun 08 '11 at 05:29
  • @irreputable: That's no mistake. Just because `InputStream` does nothing doesn't mean concrete subclasses do nothing. They might flush before releasing the stream (and a lot of them do). `InputStream` declares the contract and this contract allows for errors on closing a stream. – musiKk Jun 08 '11 at 07:06
  • 1
    @Jon: I'm calling `write(byte[])` from within a subclass of `ByteArrayOutputStream`. `BAOS` does not override this method, so I'm actually the method defined in `OutputStream` (which does throw an `IOE`) – Tony the Pony Jun 08 '11 at 07:25
  • 1
    @Jen: Ah, right. That makes sense. You could always just call `write(data, 0, data.length)` yourself. – Jon Skeet Jun 08 '11 at 07:26
  • @Jon: Yes, that's the best approach -- really strange that `write(byte[])` isn't overridden... – Tony the Pony Jun 08 '11 at 07:35
  • @Jen: Well, the override wouldn't actually have any different code - it would have the same code as the base class, just without the exception declaration. It's a bit of an odd case :) – Jon Skeet Jun 08 '11 at 07:40
  • @Jon: True... it would duplicate the call to `write(byte[],int,int)`, but at least it would keep the API consistent (throwing vs. not throwing) – Tony the Pony Jun 08 '11 at 08:39
  • @musiKk see javadoc on ByteArrayOutputStream.close() – irreputable Jun 08 '11 at 11:47
  • @irreputable: Ah. My comment referred to `InputStream`. The exception on `close` in `ByteArrayOutputStream` is indeed queer. – musiKk Jun 08 '11 at 11:51
4

Since Java 11, there is also a new method ByteArrayOutputStream.writeBytes(byte[]) which does not throw an IOException as well:

/**
 * Writes the complete contents of the specified byte array
 * to this {@code ByteArrayOutputStream}.
 *
 * ...
 *
 * @since   11
 */
public void writeBytes(byte b[]) {
    write(b, 0, b.length);
}

You could use this method if you don't want to handle an IOException which is never thrown.

Naman
  • 27,789
  • 26
  • 218
  • 353
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • I could see in Java 8 a method `write(byte b[], int off, int len)` which is [what the newly introduced syntax also makes a call to](https://stackoverflow.com/questions/18575480/how-to-convert-byte-array-to-bytearrayoutputstream/51789541#51789541).. Point being, the existing method also [didn't throw an IOException as well.](https://stackoverflow.com/a/50739082/1746118) – Naman Sep 14 '18 at 04:26
2

I just noticed that ByteArrayOutputStream.write doesn't in fact declare IOException -- but Eclipse complains about an unhandled exception whenever I use it... strange.

That's easy to explain. You've probably done something like this:

    OutputStream os = new ByteArrayOutputStream();
    ...
    os.write();

The "problem" is that you are calling the method as OutputStream.write() rather than as ByteArrayOutputStream.write(). So the compiler says:

"Ah ... write() on an OutputStream can throw an IOException, so you gotta deal with it."

It cannot say:

"This particular OutputStream is really a ByteArrayOutputStream ... so we'll let you off."

because the JLS doesn't allow it.

This is one of those edge cases where following "best practice" by coding to the interface rather than the implementation class comes back to bite you.

OK so ...

  • its a gentle nip, not a full-on bite.
  • OutputStream is implemented as a Java class not a Java interface, but that is beside the point.
  • most compilers don't actually hold conversations with you while compiling your code :-)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • In general you're right. However `ByteArrayOutputStream` unintelligently redeclares `close()` doing nothing and throwing `IOException` so in this case the reference type doesn't matter (OpenJDK). – musiKk Jun 08 '11 at 07:11
  • Thanks, great explanation. I found out what's going on. I'm calling `write(byte[])` from within a subclass of `ByteArrayOutputStream`. `BAOS` does not override this method, so I'm actually the method defined in `OutputStream` (which does throw an `IOE`) – Tony the Pony Jun 08 '11 at 07:27
1

There is an enhancement ticket for this issue since 2002. The reason why this does not get fixed, is that it would impact compatibility with previous java versions.

Here follow 2 workarounds that I would consider.

Workaround 1

The write(byte[], int, int) method does not throw checked exceptions. It is a bit more verbose to specify the 2 additional parameters. But all by all the footprint is smaller without the try-catch.

baos.write(array, 0, array.length);

Workaround 2

Another possible solution, is to write your own ByteUtil class, which catches the exception internally.

public final class ByteUtil
{
  public static void write(ByteArrayOutputStream baos, byte[] bytes)
  {
    try
    {
      baos.write(bytes);
    }
    catch (IOException e)
    {
      // impossible
    }
  }
}

// usage
ByteUtil.write(baos, bytes);
bvdb
  • 22,839
  • 10
  • 110
  • 123
1

A typical cliche is to throw new RuntimeException(theIOException) in the catch block. If the impossible happens, you at least find out about it.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
1

Exception chaining is the best practice in this situation. i.e throw a RuntimeException.

Basanth Roy
  • 6,272
  • 5
  • 25
  • 25