diff -r 2802bc494dcd src/java.base/share/classes/java/lang/String.java
--- a/src/java.base/share/classes/java/lang/String.java	Fri May 29 12:00:19 2015 +0200
+++ b/src/java.base/share/classes/java/lang/String.java	Tue Jun 02 18:53:35 2015 +0300
@@ -126,7 +126,7 @@
      * UTF16
      *
      */
-    private byte coder;
+    private final byte coder;
 
     /** Cache the hash code for the string */
     private int hash; // Default to 0
@@ -180,7 +180,7 @@
      *         The initial value of the string
      */
     public String(char value[]) {
-        this.value = initBytes(value, 0, value.length);
+        this(value, 0, value.length, null);
     }
 
     /**
@@ -205,23 +205,21 @@
      *          {@code offset} is greater than {@code value.length - count}
      */
     public String(char value[], int offset, int count) {
+        this(value, offset, count, rangeCheck(value, offset, count));
+    }
+
+    private static Void rangeCheck(char[] value, int offset, int count) {
         if (offset < 0) {
             throw new StringIndexOutOfBoundsException(offset);
         }
-        if (count <= 0) {
-            if (count < 0) {
-                throw new StringIndexOutOfBoundsException(count);
-            }
-            if (offset <= value.length) {
-                this.value = "".value;
-                return;
-            }
+        if (count < 0) {
+            throw new StringIndexOutOfBoundsException(count);
         }
         // Note: offset or count might be near -1>>>1.
         if (offset > value.length - count) {
             throw new StringIndexOutOfBoundsException(offset + count);
         }
-        this.value = initBytes(value, offset, count);
+        return null;
     }
 
     /**
@@ -262,6 +260,7 @@
             }
             if (offset <= codePoints.length) {
                 this.value = "".value;
+                this.coder = LATIN1;
                 return;
             }
         }
@@ -574,29 +573,6 @@
         this(bytes, 0, bytes.length);
     }
 
-    private byte[] initBytes(AbstractStringBuilder asb) {
-        byte[] val = asb.getValue();
-        int length = asb.length();
-        if (asb.isLatin1()) {
-            this.coder = LATIN1;
-            return Arrays.copyOfRange(val, 0, length);
-        } else {
-            if (StringUTF16.firstUTF16(val, 0, length) >= length) {
-                // deflate
-                byte[] buf = new byte[length];
-                for (int i = 0; i < length; i++) {
-                    buf[i] = (byte)StringUTF16.getChar(val, i);
-                }
-                this.coder = LATIN1;
-                return buf;
-
-            } else {
-                this.coder = UTF16;
-                return Arrays.copyOfRange(val, 0, length << 1);
-            }
-        }
-    }
-
     /**
      * Allocates a new string that contains the sequence of characters
      * currently contained in the string buffer argument. The contents of the
@@ -607,9 +583,7 @@
      *         A {@code StringBuffer}
      */
     public String(StringBuffer buffer) {
-        synchronized(buffer) {
-           this.value = initBytes(buffer);
-        }
+        this(buffer.toString());
     }
 
     /**
@@ -628,7 +602,7 @@
      * @since  1.5
      */
     public String(StringBuilder builder) {
-        this.value = initBytes(builder);
+        this(builder, null);
     }
 
    /*
@@ -641,7 +615,7 @@
     // should be removed if they all have a byte[] version
     String(char[] val, boolean share) {
         // assert share : "unshared not supported";
-        this.value = initBytes(val, 0, val.length);
+        this(val, 0, val.length, null);
     }
 
     /**
@@ -3024,20 +2998,54 @@
     }
 
     /*
+     * Package private constructor. Trailing Void argument is there for
+     * disambiguating it against other (public) constructors.
+     *
      * Stores the char[] value into a byte[] that each byte represents
      * the8 low-order bits of the corresponding character, if the char[]
      * contains only latin1 character. Or a byte[] that stores all
      * characters in their byte sequences defined by the {@code StringUTF16}.
      */
-    private byte[] initBytes(char[] value, int off, int len) {
+    String(char[] value, int off, int len, Void sig) {
+        if (len == 0) {
+            this.value = "".value;
+            this.coder = LATIN1;
+            return;
+        }
         byte[] val = StringLatin1.toBytes(value, off, len);
         if (val != null) {
+            this.value = val;
             this.coder = LATIN1;
         } else {                        // value has non-latin1 char
             this.coder = UTF16;
-            val = StringUTF16.toBytes(value, off, len);
+            this.value = StringUTF16.toBytes(value, off, len);
         }
-        return val;
+    }
+
+    /*
+     * Package private constructor. Trailing Void argument is there for
+     * disambiguating it against other (public) constructors.
+     */
+    String(AbstractStringBuilder asb, Void sig) {
+        byte[] val = asb.getValue();
+        int length = asb.length();
+        if (asb.isLatin1()) {
+            this.coder = LATIN1;
+            this.value = Arrays.copyOfRange(val, 0, length);
+        } else {
+            if (StringUTF16.firstUTF16(val, 0, length) >= length) {
+                // deflate
+                byte[] buf = new byte[length];
+                for (int i = 0; i < length; i++) {
+                    buf[i] = (byte)StringUTF16.getChar(val, i);
+                }
+                this.coder = LATIN1;
+                this.value = buf;
+            } else {
+                this.coder = UTF16;
+                this.value = Arrays.copyOfRange(val, 0, length << 1);
+            }
+        }
     }
 
    /*

