From dee9d96a418396e430d698af5e08ef7d57b52e15 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Sat, 17 Jan 2026 18:11:05 +0100 Subject: [PATCH] Update per latest feedback --- .../java/io/ByteArrayOutputStream.java | 38 +++++++------------ .../ByteArrayOutputStream/EnsureCapacity.java | 35 +++++++++++++++++ 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java index e46bf738b48..22842072687 100644 --- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java +++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java @@ -34,18 +34,23 @@ import jdk.internal.util.ArraysSupport; /** * This class implements an output stream in which the data is * written into a byte array. The buffer automatically grows as data - * is written to it. - * The data can be retrieved using {@code toByteArray()} and - * {@code toString()}. + * is written to it. The data can be retrieved using {@code toByteArray()} + * and {@code toString()}. + * *

* Closing a {@code ByteArrayOutputStream} has no effect. The methods in * this class can be called after the stream has been closed without * generating an {@code IOException}. * + *

+ * Subclasses of this class may override {@code ensureCapacity(int)} in + * order to customize the buffer growth behavior. Subclasses which add + * additional write methods should either manage buffer growth manually + * or invoke {@code ensureCapacity(int)} to grow the buffer. + * * @author Arthur van Hoff * @since 1.0 */ - public class ByteArrayOutputStream extends OutputStream { /** @@ -81,22 +86,6 @@ public class ByteArrayOutputStream extends OutputStream { buf = new byte[size]; } - /** - * Increases the capacity if necessary to ensure that this - * {@code ByteArrayOutputStream} can hold at least the number of - * elements specified by the {@code minCapacity} argument. - * If the {@code minCapacity} argument is nonpositive, this - * method takes no action and simply returns. - * - * @param minCapacity the desired minimum capacity. - * @since 27 - */ - protected void ensureCapacity(int minCapacity) { - if (minCapacity > 0) { - ensureCapacityInternal(minCapacity); - } - } - /** * Increases the capacity if necessary to ensure that this * {@code ByteArrayOutputStream} can hold at least the number of @@ -105,10 +94,11 @@ public class ByteArrayOutputStream extends OutputStream { * @param minCapacity the desired minimum capacity. * @throws OutOfMemoryError if {@code minCapacity < 0} and * {@code minCapacity - buf.length > 0}. This is interpreted as a - * request for the unsatisfiably large capacity. + * request for the unsatisfiably large capacity * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}. + * @since 27 */ - private void ensureCapacityInternal(int minCapacity) { + protected void ensureCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = buf.length; int minGrowth = minCapacity - oldCapacity; @@ -125,7 +115,7 @@ public class ByteArrayOutputStream extends OutputStream { */ @Override public synchronized void write(int b) { - ensureCapacityInternal(count + 1); + ensureCapacity(count + 1); buf[count] = (byte) b; count += 1; } @@ -145,7 +135,7 @@ public class ByteArrayOutputStream extends OutputStream { @Override public synchronized void write(byte[] b, int off, int len) { Objects.checkFromIndexSize(off, len, b.length); - ensureCapacityInternal(count + len); + ensureCapacity(count + len); System.arraycopy(b, off, buf, count, len); count += len; } diff --git a/test/jdk/java/io/ByteArrayOutputStream/EnsureCapacity.java b/test/jdk/java/io/ByteArrayOutputStream/EnsureCapacity.java index 8c0230a534b..aded8f14102 100644 --- a/test/jdk/java/io/ByteArrayOutputStream/EnsureCapacity.java +++ b/test/jdk/java/io/ByteArrayOutputStream/EnsureCapacity.java @@ -71,6 +71,23 @@ public class EnsureCapacity { byte[] actual = out.toByteArray(); byte[] expected = new byte[] { 1, 2, 3, 4, 5, 6 }; assertEquals(expected, actual); + + // verify that overriding ensureCapacity() affects behavior of standard write methods + + EvenOutputStream out2 = new EvenOutputStream(); + assertEquals(0, out2.getBufferLength()); + + out2.write(89); + assertEquals(2, out2.getBufferLength()); + + out2.write(12); + assertEquals(2, out2.getBufferLength()); + + out2.write(new byte[] { 1, 2, 3 }, 0, 3); + assertEquals(6, out2.getBufferLength()); + + out2.write(77); + assertEquals(6, out2.getBufferLength()); } private static void assertAtLeast(int actual, int min) { @@ -95,6 +112,7 @@ public class EnsureCapacity { } } + // provides extra visibility into internals private static final class TestOutputStream extends ByteArrayOutputStream { public void ensureCapacity(int minCapacity) { super.ensureCapacity(minCapacity); @@ -103,4 +121,21 @@ public class EnsureCapacity { return buf.length; } } + + // starts empty, is always sized to an even number of bytes + private static final class EvenOutputStream extends ByteArrayOutputStream { + public EvenOutputStream() { + super(0); + } + protected void ensureCapacity(int minCapacity) { + int deficit = minCapacity - buf.length; + if (deficit > 0) { + minCapacity += minCapacity % 2; + buf = Arrays.copyOf(buf, minCapacity); + } + } + public int getBufferLength() { + return buf.length; + } + } }