title: Why does Java's CharsetEncoder define .onMalformedInput()/CharsetDecoder define .onUnmappableCharacter()?
body: <p>A <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/charset/CharsetDecoder.html" rel="nofollow"><code>CharsetDecoder</code></a> basically helps decoding a sequence of <code>bytes</code> into a sequence of <code>char</code>s (see <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#newDecoder--" rel="nofollow"><code>Charset#newDecoder()</code></a>). On the opposite side, a <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/charset/CharsetEncoder.html" rel="nofollow"><code>CharsetEncoder</code></a> (see <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#newEncoder--" rel="nofollow"><code>Charset#newEncoder()</code></a>) does the reverse: take a sequence of <code>char</code>s, and encode them into a sequence of <code>byte</code>s.</p>
  
  <p><code>CharsetDecoder</code> defines <code>.onMalformedInput()</code> and it seems logical (some byte sequence may not translate to a valid <code>char</code> sequence); but why <code>.onUnmappableCharacter()</code> since its input is a byte sequence?</p>
  
  <p>Similarly, <code>CharsetEncoder</code> defines <code>.onUnmappableCharacter()</code> which is, here again, logical (for instance, if your charset is ASCII, you cannot encode <code>ö</code>); but why does it also define <code>.onMalformedInput()</code> since its input is a character sequence?</p>
  
  <p>This is all the more intriguing that you cannot obtain an encoder from a decoder and vice versa, and none of these two classes seem to share a common ancestor...</p>
  
  <hr>
  
  <p><strong>EDIT 1</strong></p>
  
  <p>It is indeed possible to trigger <code>.onMalformedInput()</code> on a <code>CharsetEncoder</code>. You "just" have to provide an illegal <code>char</code> or <code>char</code> sequence. The program below relies on the fact that in UTF-16, a high surrogate must be followed by a low surrogate; here, a two-element char array is built with two high surrogates instead and an attempt to encode it is done. <strong>NOTE how the creation of a <code>String</code> from such an ill-formed char sequence throws no exception at all</strong>:</p>
  
  <p>Code:</p>
  
  <pre><code>public static void main(final String... args)
      throws CharacterCodingException
  {
      boolean found = false;
      char c = '.';
  
      for (int i = 0; i &lt; 65536; i++) {
          if (Character.isHighSurrogate((char) i)) {
              c = (char) i;
              found = true;
              break;
          }
      }
      if (!found)
          throw new IllegalStateException();
  
      System.out.println("found: " + Integer.toHexString(c));
      final char[] foo = { c, c };
  
      new String(foo); // &lt;-- DOES NOT THROW AN EXCEPTION!!!
  
      final CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder()
          .onMalformedInput(CodingErrorAction.REPORT);
  
      encoder.encode(CharBuffer.wrap(foo));
  }
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>found: d800
  Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
      at java.nio.charset.CoderResult.throwException(CoderResult.java:277)
      at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:798)
      at com.github.fge.largetext.LargeText.main(LargeText.java:166)
  </code></pre>
  
  <hr>
  
  <p><strong>EDIT 2</strong> But now, how about the reverse? From @Kairos's answer below, quoting the manpage:</p>
  
  <blockquote>
    <p>UnmappableCharacterException - If the byte sequence starting at the input buffer's current position cannot be mapped to an equivalent character sequence and the current unmappable-character action is CodingErrorAction.REPORT</p>
  </blockquote>
  
  <p>Now, what is "cannot be mapped to an equivalent character sequence"? </p>
  
  <p>I play quite a bit with <code>CharsetDecoder</code>s in <a href="https://github.com/fge/largetext" rel="nofollow">this project</a> and have yet to produce such an error. I know how to reproduce an error in which, for instance, you only have two bytes out of a three-byte UTF-8 sequence but this triggers a <code>MalformedInputException</code>. All you have to do in this case is restart the decoding from the last known position of the <code>ByteBuffer</code>.</p>
  
  <p>Triggering an <code>UnmappableCharacterException</code> would basically mean that the <em>character encoding itself</em> would allow for an illegal <code>char</code> to be generated; or an illegal Unicode code point.</p>
  
  <p>Is this possible at all?</p>