jdk/src/java.base/share/classes/java/nio/channels/Channels.java
changeset 27933 2e48c9e946a7
parent 25859 3317bb8137f4
child 28569 20682992a0ff
equal deleted inserted replaced
27932:654c0f23c1c0 27933:2e48c9e946a7
     1 /*
     1 /*
     2  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    36 import java.nio.charset.Charset;
    36 import java.nio.charset.Charset;
    37 import java.nio.charset.CharsetDecoder;
    37 import java.nio.charset.CharsetDecoder;
    38 import java.nio.charset.CharsetEncoder;
    38 import java.nio.charset.CharsetEncoder;
    39 import java.nio.charset.UnsupportedCharsetException;
    39 import java.nio.charset.UnsupportedCharsetException;
    40 import java.nio.channels.spi.AbstractInterruptibleChannel;
    40 import java.nio.channels.spi.AbstractInterruptibleChannel;
       
    41 import java.util.Objects;
    41 import java.util.concurrent.ExecutionException;
    42 import java.util.concurrent.ExecutionException;
    42 import sun.nio.ch.ChannelInputStream;
    43 import sun.nio.ch.ChannelInputStream;
    43 import sun.nio.cs.StreamDecoder;
    44 import sun.nio.cs.StreamDecoder;
    44 import sun.nio.cs.StreamEncoder;
    45 import sun.nio.cs.StreamEncoder;
    45 
    46 
    46 
    47 
    47 /**
    48 /**
    48  * Utility methods for channels and streams.
    49  * Utility methods for channels and streams.
    49  *
    50  *
    50  * <p> This class defines static methods that support the interoperation of the
    51  * <p> This class defines static methods that support the interoperation of the
    51  * stream classes of the <tt>{@link java.io}</tt> package with the channel
    52  * stream classes of the {@link java.io} package with the channel classes
    52  * classes of this package.  </p>
    53  * of this package.  </p>
    53  *
    54  *
    54  *
    55  *
    55  * @author Mark Reinhold
    56  * @author Mark Reinhold
    56  * @author Mike McCloskey
    57  * @author Mike McCloskey
    57  * @author JSR-51 Expert Group
    58  * @author JSR-51 Expert Group
    58  * @since 1.4
    59  * @since 1.4
    59  */
    60  */
    60 
    61 
    61 public final class Channels {
    62 public final class Channels {
    62 
    63 
    63     private Channels() { }              // No instantiation
    64     private Channels() { throw new Error("no instances"); }
    64 
       
    65     private static void checkNotNull(Object o, String name) {
       
    66         if (o == null)
       
    67             throw new NullPointerException("\"" + name + "\" is null!");
       
    68     }
       
    69 
    65 
    70     /**
    66     /**
    71      * Write all remaining bytes in buffer to the given channel.
    67      * Write all remaining bytes in buffer to the given channel.
    72      * If the channel is selectable then it must be configured blocking.
    68      * If the channel is selectable then it must be configured blocking.
    73      */
    69      */
    89      */
    85      */
    90     private static void writeFully(WritableByteChannel ch, ByteBuffer bb)
    86     private static void writeFully(WritableByteChannel ch, ByteBuffer bb)
    91         throws IOException
    87         throws IOException
    92     {
    88     {
    93         if (ch instanceof SelectableChannel) {
    89         if (ch instanceof SelectableChannel) {
    94             SelectableChannel sc = (SelectableChannel)ch;
    90             SelectableChannel sc = (SelectableChannel) ch;
    95             synchronized (sc.blockingLock()) {
    91             synchronized (sc.blockingLock()) {
    96                 if (!sc.isBlocking())
    92                 if (!sc.isBlocking())
    97                     throw new IllegalBlockingModeException();
    93                     throw new IllegalBlockingModeException();
    98                 writeFullyImpl(ch, bb);
    94                 writeFullyImpl(ch, bb);
    99             }
    95             }
   105     // -- Byte streams from channels --
   101     // -- Byte streams from channels --
   106 
   102 
   107     /**
   103     /**
   108      * Constructs a stream that reads bytes from the given channel.
   104      * Constructs a stream that reads bytes from the given channel.
   109      *
   105      *
   110      * <p> The <tt>read</tt> methods of the resulting stream will throw an
   106      * <p> The {@code read} methods of the resulting stream will throw an
   111      * {@link IllegalBlockingModeException} if invoked while the underlying
   107      * {@link IllegalBlockingModeException} if invoked while the underlying
   112      * channel is in non-blocking mode.  The stream will not be buffered, and
   108      * channel is in non-blocking mode.  The stream will not be buffered, and
   113      * it will not support the {@link InputStream#mark mark} or {@link
   109      * it will not support the {@link InputStream#mark mark} or {@link
   114      * InputStream#reset reset} methods.  The stream will be safe for access by
   110      * InputStream#reset reset} methods.  The stream will be safe for access by
   115      * multiple concurrent threads.  Closing the stream will in turn cause the
   111      * multiple concurrent threads.  Closing the stream will in turn cause the
   119      *         The channel from which bytes will be read
   115      *         The channel from which bytes will be read
   120      *
   116      *
   121      * @return  A new input stream
   117      * @return  A new input stream
   122      */
   118      */
   123     public static InputStream newInputStream(ReadableByteChannel ch) {
   119     public static InputStream newInputStream(ReadableByteChannel ch) {
   124         checkNotNull(ch, "ch");
   120         Objects.requireNonNull(ch, "ch");
   125         return new sun.nio.ch.ChannelInputStream(ch);
   121         return new ChannelInputStream(ch);
   126     }
   122     }
   127 
   123 
   128     /**
   124     /**
   129      * Constructs a stream that writes bytes to the given channel.
   125      * Constructs a stream that writes bytes to the given channel.
   130      *
   126      *
   131      * <p> The <tt>write</tt> methods of the resulting stream will throw an
   127      * <p> The {@code write} methods of the resulting stream will throw an
   132      * {@link IllegalBlockingModeException} if invoked while the underlying
   128      * {@link IllegalBlockingModeException} if invoked while the underlying
   133      * channel is in non-blocking mode.  The stream will not be buffered.  The
   129      * channel is in non-blocking mode.  The stream will not be buffered.  The
   134      * stream will be safe for access by multiple concurrent threads.  Closing
   130      * stream will be safe for access by multiple concurrent threads.  Closing
   135      * the stream will in turn cause the channel to be closed.  </p>
   131      * the stream will in turn cause the channel to be closed.  </p>
   136      *
   132      *
   137      * @param  ch
   133      * @param  ch
   138      *         The channel to which bytes will be written
   134      *         The channel to which bytes will be written
   139      *
   135      *
   140      * @return  A new output stream
   136      * @return  A new output stream
   141      */
   137      */
   142     public static OutputStream newOutputStream(final WritableByteChannel ch) {
   138     public static OutputStream newOutputStream(WritableByteChannel ch) {
   143         checkNotNull(ch, "ch");
   139         Objects.requireNonNull(ch, "ch");
   144 
   140 
   145         return new OutputStream() {
   141         return new OutputStream() {
   146 
   142 
   147                 private ByteBuffer bb = null;
   143             private ByteBuffer bb;
   148                 private byte[] bs = null;       // Invoker's previous array
   144             private byte[] bs;       // Invoker's previous array
   149                 private byte[] b1 = null;
   145             private byte[] b1;
   150 
   146 
   151                 public synchronized void write(int b) throws IOException {
   147             @Override
   152                    if (b1 == null)
   148             public synchronized void write(int b) throws IOException {
   153                         b1 = new byte[1];
   149                 if (b1 == null)
   154                     b1[0] = (byte)b;
   150                     b1 = new byte[1];
   155                     this.write(b1);
   151                 b1[0] = (byte) b;
       
   152                 this.write(b1);
       
   153             }
       
   154 
       
   155             @Override
       
   156             public synchronized void write(byte[] bs, int off, int len)
       
   157                     throws IOException
       
   158             {
       
   159                 if ((off < 0) || (off > bs.length) || (len < 0) ||
       
   160                     ((off + len) > bs.length) || ((off + len) < 0)) {
       
   161                     throw new IndexOutOfBoundsException();
       
   162                 } else if (len == 0) {
       
   163                     return;
   156                 }
   164                 }
   157 
   165                 ByteBuffer bb = ((this.bs == bs)
   158                 public synchronized void write(byte[] bs, int off, int len)
   166                                  ? this.bb
   159                     throws IOException
   167                                  : ByteBuffer.wrap(bs));
   160                 {
   168                 bb.limit(Math.min(off + len, bb.capacity()));
   161                     if ((off < 0) || (off > bs.length) || (len < 0) ||
   169                 bb.position(off);
   162                         ((off + len) > bs.length) || ((off + len) < 0)) {
   170                 this.bb = bb;
   163                         throw new IndexOutOfBoundsException();
   171                 this.bs = bs;
   164                     } else if (len == 0) {
   172                 Channels.writeFully(ch, bb);
   165                         return;
   173             }
   166                     }
   174 
   167                     ByteBuffer bb = ((this.bs == bs)
   175             @Override
   168                                      ? this.bb
   176             public void close() throws IOException {
   169                                      : ByteBuffer.wrap(bs));
   177                 ch.close();
   170                     bb.limit(Math.min(off + len, bb.capacity()));
   178             }
   171                     bb.position(off);
   179 
   172                     this.bb = bb;
   180         };
   173                     this.bs = bs;
       
   174                     Channels.writeFully(ch, bb);
       
   175                 }
       
   176 
       
   177                 public void close() throws IOException {
       
   178                     ch.close();
       
   179                 }
       
   180 
       
   181             };
       
   182     }
   181     }
   183 
   182 
   184     /**
   183     /**
   185      * Constructs a stream that reads bytes from the given channel.
   184      * Constructs a stream that reads bytes from the given channel.
   186      *
   185      *
   194      *
   193      *
   195      * @return  A new input stream
   194      * @return  A new input stream
   196      *
   195      *
   197      * @since 1.7
   196      * @since 1.7
   198      */
   197      */
   199     public static InputStream newInputStream(final AsynchronousByteChannel ch) {
   198     public static InputStream newInputStream(AsynchronousByteChannel ch) {
   200         checkNotNull(ch, "ch");
   199         Objects.requireNonNull(ch, "ch");
   201         return new InputStream() {
   200         return new InputStream() {
   202 
   201 
   203             private ByteBuffer bb = null;
   202             private ByteBuffer bb;
   204             private byte[] bs = null;           // Invoker's previous array
   203             private byte[] bs;           // Invoker's previous array
   205             private byte[] b1 = null;
   204             private byte[] b1;
   206 
   205 
   207             @Override
   206             @Override
   208             public synchronized int read() throws IOException {
   207             public synchronized int read() throws IOException {
   209                 if (b1 == null)
   208                 if (b1 == null)
   210                     b1 = new byte[1];
   209                     b1 = new byte[1];
   214                 return -1;
   213                 return -1;
   215             }
   214             }
   216 
   215 
   217             @Override
   216             @Override
   218             public synchronized int read(byte[] bs, int off, int len)
   217             public synchronized int read(byte[] bs, int off, int len)
   219                 throws IOException
   218                     throws IOException
   220             {
   219             {
   221                 if ((off < 0) || (off > bs.length) || (len < 0) ||
   220                 if ((off < 0) || (off > bs.length) || (len < 0) ||
   222                     ((off + len) > bs.length) || ((off + len) < 0)) {
   221                     ((off + len) > bs.length) || ((off + len) < 0)) {
   223                     throw new IndexOutOfBoundsException();
   222                     throw new IndexOutOfBoundsException();
   224                 } else if (len == 0)
   223                 } else if (len == 0) {
   225                     return 0;
   224                     return 0;
       
   225                 }
   226 
   226 
   227                 ByteBuffer bb = ((this.bs == bs)
   227                 ByteBuffer bb = ((this.bs == bs)
   228                                  ? this.bb
   228                                  ? this.bb
   229                                  : ByteBuffer.wrap(bs));
   229                                  : ByteBuffer.wrap(bs));
   230                 bb.position(off);
   230                 bb.position(off);
   268      *
   268      *
   269      * @return  A new output stream
   269      * @return  A new output stream
   270      *
   270      *
   271      * @since 1.7
   271      * @since 1.7
   272      */
   272      */
   273     public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {
   273     public static OutputStream newOutputStream(AsynchronousByteChannel ch) {
   274         checkNotNull(ch, "ch");
   274         Objects.requireNonNull(ch, "ch");
   275         return new OutputStream() {
   275         return new OutputStream() {
   276 
   276 
   277             private ByteBuffer bb = null;
   277             private ByteBuffer bb;
   278             private byte[] bs = null;   // Invoker's previous array
   278             private byte[] bs;   // Invoker's previous array
   279             private byte[] b1 = null;
   279             private byte[] b1;
   280 
   280 
   281             @Override
   281             @Override
   282             public synchronized void write(int b) throws IOException {
   282             public synchronized void write(int b) throws IOException {
   283                if (b1 == null)
   283                 if (b1 == null)
   284                     b1 = new byte[1];
   284                     b1 = new byte[1];
   285                 b1[0] = (byte)b;
   285                 b1[0] = (byte) b;
   286                 this.write(b1);
   286                 this.write(b1);
   287             }
   287             }
   288 
   288 
   289             @Override
   289             @Override
   290             public synchronized void write(byte[] bs, int off, int len)
   290             public synchronized void write(byte[] bs, int off, int len)
   291                 throws IOException
   291                     throws IOException
   292             {
   292             {
   293                 if ((off < 0) || (off > bs.length) || (len < 0) ||
   293                 if ((off < 0) || (off > bs.length) || (len < 0) ||
   294                     ((off + len) > bs.length) || ((off + len) < 0)) {
   294                     ((off + len) > bs.length) || ((off + len) < 0)) {
   295                     throw new IndexOutOfBoundsException();
   295                     throw new IndexOutOfBoundsException();
   296                 } else if (len == 0) {
   296                 } else if (len == 0) {
   341      * @param  in
   341      * @param  in
   342      *         The stream from which bytes are to be read
   342      *         The stream from which bytes are to be read
   343      *
   343      *
   344      * @return  A new readable byte channel
   344      * @return  A new readable byte channel
   345      */
   345      */
   346     public static ReadableByteChannel newChannel(final InputStream in) {
   346     public static ReadableByteChannel newChannel(InputStream in) {
   347         checkNotNull(in, "in");
   347         Objects.requireNonNull(in, "in");
   348 
   348 
   349         if (in instanceof FileInputStream &&
   349         if (in.getClass() == FileInputStream.class) {
   350             FileInputStream.class.equals(in.getClass())) {
   350             return ((FileInputStream) in).getChannel();
   351             return ((FileInputStream)in).getChannel();
       
   352         }
   351         }
   353 
   352 
   354         return new ReadableByteChannelImpl(in);
   353         return new ReadableByteChannelImpl(in);
   355     }
   354     }
   356 
   355 
   357     private static class ReadableByteChannelImpl
   356     private static class ReadableByteChannelImpl
   358         extends AbstractInterruptibleChannel    // Not really interruptible
   357         extends AbstractInterruptibleChannel    // Not really interruptible
   359         implements ReadableByteChannel
   358         implements ReadableByteChannel
   360     {
   359     {
   361         InputStream in;
   360         private final InputStream in;
   362         private static final int TRANSFER_SIZE = 8192;
   361         private static final int TRANSFER_SIZE = 8192;
   363         private byte buf[] = new byte[0];
   362         private byte[] buf = new byte[0];
   364         private boolean open = true;
   363         private final Object readLock = new Object();
   365         private Object readLock = new Object();
       
   366 
   364 
   367         ReadableByteChannelImpl(InputStream in) {
   365         ReadableByteChannelImpl(InputStream in) {
   368             this.in = in;
   366             this.in = in;
   369         }
   367         }
   370 
   368 
       
   369         @Override
   371         public int read(ByteBuffer dst) throws IOException {
   370         public int read(ByteBuffer dst) throws IOException {
   372             int len = dst.remaining();
   371             int len = dst.remaining();
   373             int totalRead = 0;
   372             int totalRead = 0;
   374             int bytesRead = 0;
   373             int bytesRead = 0;
   375             synchronized (readLock) {
   374             synchronized (readLock) {
   397 
   396 
   398                 return totalRead;
   397                 return totalRead;
   399             }
   398             }
   400         }
   399         }
   401 
   400 
       
   401         @Override
   402         protected void implCloseChannel() throws IOException {
   402         protected void implCloseChannel() throws IOException {
   403             in.close();
   403             in.close();
   404             open = false;
       
   405         }
   404         }
   406     }
   405     }
   407 
   406 
   408 
   407 
   409     /**
   408     /**
   416      * @param  out
   415      * @param  out
   417      *         The stream to which bytes are to be written
   416      *         The stream to which bytes are to be written
   418      *
   417      *
   419      * @return  A new writable byte channel
   418      * @return  A new writable byte channel
   420      */
   419      */
   421     public static WritableByteChannel newChannel(final OutputStream out) {
   420     public static WritableByteChannel newChannel(OutputStream out) {
   422         checkNotNull(out, "out");
   421         Objects.requireNonNull(out, "out");
   423 
   422 
   424         if (out instanceof FileOutputStream &&
   423         if (out.getClass() == FileOutputStream.class) {
   425             FileOutputStream.class.equals(out.getClass())) {
   424             return ((FileOutputStream) out).getChannel();
   426                 return ((FileOutputStream)out).getChannel();
       
   427         }
   425         }
   428 
   426 
   429         return new WritableByteChannelImpl(out);
   427         return new WritableByteChannelImpl(out);
   430     }
   428     }
   431 
   429 
   432     private static class WritableByteChannelImpl
   430     private static class WritableByteChannelImpl
   433         extends AbstractInterruptibleChannel    // Not really interruptible
   431         extends AbstractInterruptibleChannel    // Not really interruptible
   434         implements WritableByteChannel
   432         implements WritableByteChannel
   435     {
   433     {
   436         OutputStream out;
   434         private final OutputStream out;
   437         private static final int TRANSFER_SIZE = 8192;
   435         private static final int TRANSFER_SIZE = 8192;
   438         private byte buf[] = new byte[0];
   436         private byte[] buf = new byte[0];
   439         private boolean open = true;
   437         private final Object writeLock = new Object();
   440         private Object writeLock = new Object();
       
   441 
   438 
   442         WritableByteChannelImpl(OutputStream out) {
   439         WritableByteChannelImpl(OutputStream out) {
   443             this.out = out;
   440             this.out = out;
   444         }
   441         }
   445 
   442 
       
   443         @Override
   446         public int write(ByteBuffer src) throws IOException {
   444         public int write(ByteBuffer src) throws IOException {
   447             int len = src.remaining();
   445             int len = src.remaining();
   448             int totalWritten = 0;
   446             int totalWritten = 0;
   449             synchronized (writeLock) {
   447             synchronized (writeLock) {
   450                 while (totalWritten < len) {
   448                 while (totalWritten < len) {
   463                 }
   461                 }
   464                 return totalWritten;
   462                 return totalWritten;
   465             }
   463             }
   466         }
   464         }
   467 
   465 
       
   466         @Override
   468         protected void implCloseChannel() throws IOException {
   467         protected void implCloseChannel() throws IOException {
   469             out.close();
   468             out.close();
   470             open = false;
       
   471         }
   469         }
   472     }
   470     }
   473 
   471 
   474 
   472 
   475     // -- Character streams from channels --
   473     // -- Character streams from channels --
   477     /**
   475     /**
   478      * Constructs a reader that decodes bytes from the given channel using the
   476      * Constructs a reader that decodes bytes from the given channel using the
   479      * given decoder.
   477      * given decoder.
   480      *
   478      *
   481      * <p> The resulting stream will contain an internal input buffer of at
   479      * <p> The resulting stream will contain an internal input buffer of at
   482      * least <tt>minBufferCap</tt> bytes.  The stream's <tt>read</tt> methods
   480      * least {@code minBufferCap} bytes.  The stream's {@code read} methods
   483      * will, as needed, fill the buffer by reading bytes from the underlying
   481      * will, as needed, fill the buffer by reading bytes from the underlying
   484      * channel; if the channel is in non-blocking mode when bytes are to be
   482      * channel; if the channel is in non-blocking mode when bytes are to be
   485      * read then an {@link IllegalBlockingModeException} will be thrown.  The
   483      * read then an {@link IllegalBlockingModeException} will be thrown.  The
   486      * resulting stream will not otherwise be buffered, and it will not support
   484      * resulting stream will not otherwise be buffered, and it will not support
   487      * the {@link Reader#mark mark} or {@link Reader#reset reset} methods.
   485      * the {@link Reader#mark mark} or {@link Reader#reset reset} methods.
   493      * @param  dec
   491      * @param  dec
   494      *         The charset decoder to be used
   492      *         The charset decoder to be used
   495      *
   493      *
   496      * @param  minBufferCap
   494      * @param  minBufferCap
   497      *         The minimum capacity of the internal byte buffer,
   495      *         The minimum capacity of the internal byte buffer,
   498      *         or <tt>-1</tt> if an implementation-dependent
   496      *         or {@code -1} if an implementation-dependent
   499      *         default capacity is to be used
   497      *         default capacity is to be used
   500      *
   498      *
   501      * @return  A new reader
   499      * @return  A new reader
   502      */
   500      */
   503     public static Reader newReader(ReadableByteChannel ch,
   501     public static Reader newReader(ReadableByteChannel ch,
   504                                    CharsetDecoder dec,
   502                                    CharsetDecoder dec,
   505                                    int minBufferCap)
   503                                    int minBufferCap)
   506     {
   504     {
   507         checkNotNull(ch, "ch");
   505         Objects.requireNonNull(ch, "ch");
   508         return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);
   506         return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);
   509     }
   507     }
   510 
   508 
   511     /**
   509     /**
   512      * Constructs a reader that decodes bytes from the given channel according
   510      * Constructs a reader that decodes bytes from the given channel according
   513      * to the named charset.
   511      * to the named charset.
   514      *
   512      *
   515      * <p> An invocation of this method of the form
   513      * <p> An invocation of this method of the form
   516      *
   514      *
   517      * <blockquote><pre>
   515      * <pre> {@code
   518      * Channels.newReader(ch, csname)</pre></blockquote>
   516      *     Channels.newReader(ch, csname)
       
   517      * } </pre>
   519      *
   518      *
   520      * behaves in exactly the same way as the expression
   519      * behaves in exactly the same way as the expression
   521      *
   520      *
   522      * <blockquote><pre>
   521      * <pre> {@code
   523      * Channels.newReader(ch,
   522      *     Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1)
   524      *                    Charset.forName(csName)
   523      * } </pre>
   525      *                        .newDecoder(),
       
   526      *                    -1);</pre></blockquote>
       
   527      *
   524      *
   528      * @param  ch
   525      * @param  ch
   529      *         The channel from which bytes will be read
   526      *         The channel from which bytes will be read
   530      *
   527      *
   531      * @param  csName
   528      * @param  csName
   538      *          in this instance of the Java virtual machine
   535      *          in this instance of the Java virtual machine
   539      */
   536      */
   540     public static Reader newReader(ReadableByteChannel ch,
   537     public static Reader newReader(ReadableByteChannel ch,
   541                                    String csName)
   538                                    String csName)
   542     {
   539     {
   543         checkNotNull(csName, "csName");
   540         Objects.requireNonNull(csName, "csName");
   544         return newReader(ch, Charset.forName(csName).newDecoder(), -1);
   541         return newReader(ch, Charset.forName(csName).newDecoder(), -1);
   545     }
   542     }
   546 
   543 
   547     /**
   544     /**
   548      * Constructs a writer that encodes characters using the given encoder and
   545      * Constructs a writer that encodes characters using the given encoder and
   549      * writes the resulting bytes to the given channel.
   546      * writes the resulting bytes to the given channel.
   550      *
   547      *
   551      * <p> The resulting stream will contain an internal output buffer of at
   548      * <p> The resulting stream will contain an internal output buffer of at
   552      * least <tt>minBufferCap</tt> bytes.  The stream's <tt>write</tt> methods
   549      * least {@code minBufferCap} bytes.  The stream's {@code write} methods
   553      * will, as needed, flush the buffer by writing bytes to the underlying
   550      * will, as needed, flush the buffer by writing bytes to the underlying
   554      * channel; if the channel is in non-blocking mode when bytes are to be
   551      * channel; if the channel is in non-blocking mode when bytes are to be
   555      * written then an {@link IllegalBlockingModeException} will be thrown.
   552      * written then an {@link IllegalBlockingModeException} will be thrown.
   556      * The resulting stream will not otherwise be buffered.  Closing the stream
   553      * The resulting stream will not otherwise be buffered.  Closing the stream
   557      * will in turn cause the channel to be closed.  </p>
   554      * will in turn cause the channel to be closed.  </p>
   562      * @param  enc
   559      * @param  enc
   563      *         The charset encoder to be used
   560      *         The charset encoder to be used
   564      *
   561      *
   565      * @param  minBufferCap
   562      * @param  minBufferCap
   566      *         The minimum capacity of the internal byte buffer,
   563      *         The minimum capacity of the internal byte buffer,
   567      *         or <tt>-1</tt> if an implementation-dependent
   564      *         or {@code -1} if an implementation-dependent
   568      *         default capacity is to be used
   565      *         default capacity is to be used
   569      *
   566      *
   570      * @return  A new writer
   567      * @return  A new writer
   571      */
   568      */
   572     public static Writer newWriter(final WritableByteChannel ch,
   569     public static Writer newWriter(WritableByteChannel ch,
   573                                    final CharsetEncoder enc,
   570                                    CharsetEncoder enc,
   574                                    final int minBufferCap)
   571                                    int minBufferCap)
   575     {
   572     {
   576         checkNotNull(ch, "ch");
   573         Objects.requireNonNull(ch, "ch");
   577         return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
   574         return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
   578     }
   575     }
   579 
   576 
   580     /**
   577     /**
   581      * Constructs a writer that encodes characters according to the named
   578      * Constructs a writer that encodes characters according to the named
   582      * charset and writes the resulting bytes to the given channel.
   579      * charset and writes the resulting bytes to the given channel.
   583      *
   580      *
   584      * <p> An invocation of this method of the form
   581      * <p> An invocation of this method of the form
   585      *
   582      * <p>
   586      * <blockquote><pre>
   583      * <pre> {@code
   587      * Channels.newWriter(ch, csname)</pre></blockquote>
   584      *     Channels.newWriter(ch, csname)
   588      *
   585      * } </pre>
   589      * behaves in exactly the same way as the expression
   586      * behaves in exactly the same way as the expression
   590      *
   587      * <p>
   591      * <blockquote><pre>
   588      * <pre> {@code
   592      * Channels.newWriter(ch,
   589      *     Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1)
   593      *                    Charset.forName(csName)
   590      * } </pre>
   594      *                        .newEncoder(),
       
   595      *                    -1);</pre></blockquote>
       
   596      *
   591      *
   597      * @param  ch
   592      * @param  ch
   598      *         The channel to which bytes will be written
   593      *         The channel to which bytes will be written
   599      *
   594      *
   600      * @param  csName
   595      * @param  csName
   607      *          in this instance of the Java virtual machine
   602      *          in this instance of the Java virtual machine
   608      */
   603      */
   609     public static Writer newWriter(WritableByteChannel ch,
   604     public static Writer newWriter(WritableByteChannel ch,
   610                                    String csName)
   605                                    String csName)
   611     {
   606     {
   612         checkNotNull(csName, "csName");
   607         Objects.requireNonNull(csName, "csName");
   613         return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
   608         return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
   614     }
   609     }
   615 }
   610 }