code: public static String decode(String s) {
          int n = s.length();
          if ((n == 0) || (s.indexOf('%') < 0))
              return s;
  
          StringBuilder sb = new StringBuilder(n);
          ByteBuffer bb = ByteBuffer.allocate(n);
          CharBuffer cb = CharBuffer.allocate(n);
          CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
              .onMalformedInput(CodingErrorAction.REPORT)
              .onUnmappableCharacter(CodingErrorAction.REPORT);
  
          char c = s.charAt(0);
          for (int i = 0; i < n;) {
              assert c == s.charAt(i);
              if (c != '%') {
                  sb.append(c);
                  if (++i >= n)
                      break;
                  c = s.charAt(i);
                  continue;
              }
              bb.clear();
              int ui = i;
              for (;;) {
                  assert (n - i >= 2);
                  try {
                      bb.put(unescape(s, i));
                  } catch (NumberFormatException e) {
                      throw new IllegalArgumentException();
                  }
                  i += 3;
                  if (i >= n)
                      break;
                  c = s.charAt(i);
                  if (c != '%')
                      break;
              }
              bb.flip();
              cb.clear();
              dec.reset();
              CoderResult cr = dec.decode(bb, cb, true);
              if (cr.isError())
                  throw new IllegalArgumentException("Error decoding percent encoded characters");
              cr = dec.flush(cb);
              if (cr.isError())
                  throw new IllegalArgumentException("Error decoding percent encoded characters");
              sb.append(cb.flip().toString());
          }
  
          return sb.toString();
      }
docs: Returns a new String constructed from the specified String by replacing
  the URL escape sequences and UTF8 encoding with the characters they
  represent.