View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.text;
18  
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.Serializable;
22  import java.io.Writer;
23  import java.nio.CharBuffer;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Objects;
27  
28  import org.apache.commons.lang3.ArrayUtils;
29  import org.apache.commons.lang3.CharUtils;
30  import org.apache.commons.lang3.StringUtils;
31  import org.apache.commons.lang3.builder.Builder;
32  
33  /**
34   * Builds a string from constituent parts providing a more flexible and powerful API
35   * than StringBuffer.
36   * <p>
37   * The main differences from StringBuffer/StringBuilder are:
38   * </p>
39   * <ul>
40   * <li>Not synchronized</li>
41   * <li>Not final</li>
42   * <li>Subclasses have direct access to character array</li>
43   * <li>Additional methods
44   *  <ul>
45   *   <li>appendWithSeparators - adds an array of values, with a separator</li>
46   *   <li>appendPadding - adds a length padding characters</li>
47   *   <li>appendFixedLength - adds a fixed width field to the builder</li>
48   *   <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
49   *   <li>delete - delete char or string</li>
50   *   <li>replace - search and replace for a char or string</li>
51   *   <li>leftString/rightString/midString - substring without exceptions</li>
52   *   <li>contains - whether the builder contains a char or string</li>
53   *   <li>size/clear/isEmpty - collections style API methods</li>
54   *  </ul>
55   * </li>
56   * <li>Views
57   *  <ul>
58   *   <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
59   *   <li>asReader - uses the internal buffer as the source of a Reader</li>
60   *   <li>asWriter - allows a Writer to write directly to the internal buffer</li>
61   *  </ul>
62   * </li>
63   * </ul>
64   * <p>
65   * The aim has been to provide an API that mimics very closely what StringBuffer
66   * provides, but with additional methods. It should be noted that some edge cases,
67   * with invalid indices or null input, have been altered - see individual methods.
68   * The biggest of these changes is that by default, null will not output the text
69   * 'null'. This can be controlled by a property, {@link #setNullText(String)}.
70   * <p>
71   * Prior to 3.0, this class implemented Cloneable but did not implement the
72   * clone method so could not be used. From 3.0 onwards it no longer implements
73   * the interface.
74   *
75   * @since 2.2
76   * @deprecated as of 3.6, use commons-text
77   * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/TextStringBuilder.html">
78   * TextStringBuilder</a> instead
79   */
80  @Deprecated
81  public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
82  
83      /**
84       * The extra capacity for new builders.
85       */
86      static final int CAPACITY = 32;
87  
88      /**
89       * Required for serialization support.
90       *
91       * @see java.io.Serializable
92       */
93      private static final long serialVersionUID = 7628716375283629643L;
94  
95      /** Internal data storage. */
96      protected char[] buffer; // TODO make private?
97      /** Current size of the buffer. */
98      protected int size; // TODO make private?
99      /** The new line. */
100     private String newLine;
101     /** The null text. */
102     private String nullText;
103 
104     //-----------------------------------------------------------------------
105     /**
106      * Constructor that creates an empty builder initial capacity 32 characters.
107      */
108     public StrBuilder() {
109         this(CAPACITY);
110     }
111 
112     /**
113      * Constructor that creates an empty builder the specified initial capacity.
114      *
115      * @param initialCapacity  the initial capacity, zero or less will be converted to 32
116      */
117     public StrBuilder(int initialCapacity) {
118         if (initialCapacity <= 0) {
119             initialCapacity = CAPACITY;
120         }
121         buffer = new char[initialCapacity];
122     }
123 
124     /**
125      * Constructor that creates a builder from the string, allocating
126      * 32 extra characters for growth.
127      *
128      * @param str  the string to copy, null treated as blank string
129      */
130     public StrBuilder(final String str) {
131         if (str == null) {
132             buffer = new char[CAPACITY];
133         } else {
134             buffer = new char[str.length() + CAPACITY];
135             append(str);
136         }
137     }
138 
139     //-----------------------------------------------------------------------
140     /**
141      * Gets the text to be appended when a new line is added.
142      *
143      * @return the new line text, null means use system default
144      */
145     public String getNewLineText() {
146         return newLine;
147     }
148 
149     /**
150      * Sets the text to be appended when a new line is added.
151      *
152      * @param newLine  the new line text, null means use system default
153      * @return this, to enable chaining
154      */
155     public StrBuilder setNewLineText(final String newLine) {
156         this.newLine = newLine;
157         return this;
158     }
159 
160     //-----------------------------------------------------------------------
161     /**
162      * Gets the text to be appended when null is added.
163      *
164      * @return the null text, null means no append
165      */
166     public String getNullText() {
167         return nullText;
168     }
169 
170     /**
171      * Sets the text to be appended when null is added.
172      *
173      * @param nullText  the null text, null means no append
174      * @return this, to enable chaining
175      */
176     public StrBuilder setNullText(String nullText) {
177         if (nullText != null && nullText.isEmpty()) {
178             nullText = null;
179         }
180         this.nullText = nullText;
181         return this;
182     }
183 
184     //-----------------------------------------------------------------------
185     /**
186      * Gets the length of the string builder.
187      *
188      * @return the length
189      */
190     @Override
191     public int length() {
192         return size;
193     }
194 
195     /**
196      * Updates the length of the builder by either dropping the last characters
197      * or adding filler of Unicode zero.
198      *
199      * @param length  the length to set to, must be zero or positive
200      * @return this, to enable chaining
201      * @throws IndexOutOfBoundsException if the length is negative
202      */
203     public StrBuilder setLength(final int length) {
204         if (length < 0) {
205             throw new StringIndexOutOfBoundsException(length);
206         }
207         if (length < size) {
208             size = length;
209         } else if (length > size) {
210             ensureCapacity(length);
211             final int oldEnd = size;
212             final int newEnd = length;
213             size = length;
214             for (int i = oldEnd; i < newEnd; i++) {
215                 buffer[i] = CharUtils.NUL;
216             }
217         }
218         return this;
219     }
220 
221     //-----------------------------------------------------------------------
222     /**
223      * Gets the current size of the internal character array buffer.
224      *
225      * @return the capacity
226      */
227     public int capacity() {
228         return buffer.length;
229     }
230 
231     /**
232      * Checks the capacity and ensures that it is at least the size specified.
233      *
234      * @param capacity  the capacity to ensure
235      * @return this, to enable chaining
236      */
237     public StrBuilder ensureCapacity(final int capacity) {
238         if (capacity > buffer.length) {
239             final char[] old = buffer;
240             buffer = new char[capacity * 2];
241             System.arraycopy(old, 0, buffer, 0, size);
242         }
243         return this;
244     }
245 
246     /**
247      * Minimizes the capacity to the actual length of the string.
248      *
249      * @return this, to enable chaining
250      */
251     public StrBuilder minimizeCapacity() {
252         if (buffer.length > length()) {
253             final char[] old = buffer;
254             buffer = new char[length()];
255             System.arraycopy(old, 0, buffer, 0, size);
256         }
257         return this;
258     }
259 
260     //-----------------------------------------------------------------------
261     /**
262      * Gets the length of the string builder.
263      * <p>
264      * This method is the same as {@link #length()} and is provided to match the
265      * API of Collections.
266      *
267      * @return the length
268      */
269     public int size() {
270         return size;
271     }
272 
273     /**
274      * Checks is the string builder is empty (convenience Collections API style method).
275      * <p>
276      * This method is the same as checking {@link #length()} and is provided to match the
277      * API of Collections.
278      *
279      * @return {@code true} if the size is {@code 0}.
280      */
281     public boolean isEmpty() {
282         return size == 0;
283     }
284 
285     /**
286      * Checks is the string builder is not empty (convenience Collections API style method).
287      * <p>
288      * This method is the same as checking {@link #length()} and is provided to match the
289      * API of Collections.
290      *
291      * @return {@code true} if the size is greater than {@code 0}.
292      * @since 3.12.0
293      */
294     public boolean isNotEmpty() {
295         return size > 0;
296     }
297 
298     /**
299      * Clears the string builder (convenience Collections API style method).
300      * <p>
301      * This method does not reduce the size of the internal character buffer.
302      * To do that, call {@code clear()} followed by {@link #minimizeCapacity()}.
303      * <p>
304      * This method is the same as {@link #setLength(int)} called with zero
305      * and is provided to match the API of Collections.
306      *
307      * @return this, to enable chaining
308      */
309     public StrBuilder clear() {
310         size = 0;
311         return this;
312     }
313 
314     //-----------------------------------------------------------------------
315     /**
316      * Gets the character at the specified index.
317      *
318      * @see #setCharAt(int, char)
319      * @see #deleteCharAt(int)
320      * @param index  the index to retrieve, must be valid
321      * @return the character at the index
322      * @throws IndexOutOfBoundsException if the index is invalid
323      */
324     @Override
325     public char charAt(final int index) {
326         if (index < 0 || index >= length()) {
327             throw new StringIndexOutOfBoundsException(index);
328         }
329         return buffer[index];
330     }
331 
332     /**
333      * Sets the character at the specified index.
334      *
335      * @see #charAt(int)
336      * @see #deleteCharAt(int)
337      * @param index  the index to set
338      * @param ch  the new character
339      * @return this, to enable chaining
340      * @throws IndexOutOfBoundsException if the index is invalid
341      */
342     public StrBuilder setCharAt(final int index, final char ch) {
343         if (index < 0 || index >= length()) {
344             throw new StringIndexOutOfBoundsException(index);
345         }
346         buffer[index] = ch;
347         return this;
348     }
349 
350     /**
351      * Deletes the character at the specified index.
352      *
353      * @see #charAt(int)
354      * @see #setCharAt(int, char)
355      * @param index  the index to delete
356      * @return this, to enable chaining
357      * @throws IndexOutOfBoundsException if the index is invalid
358      */
359     public StrBuilder deleteCharAt(final int index) {
360         if (index < 0 || index >= size) {
361             throw new StringIndexOutOfBoundsException(index);
362         }
363         deleteImpl(index, index + 1, 1);
364         return this;
365     }
366 
367     //-----------------------------------------------------------------------
368     /**
369      * Copies the builder's character array into a new character array.
370      *
371      * @return a new array that represents the contents of the builder
372      */
373     public char[] toCharArray() {
374         if (size == 0) {
375             return ArrayUtils.EMPTY_CHAR_ARRAY;
376         }
377         final char[] chars = new char[size];
378         System.arraycopy(buffer, 0, chars, 0, size);
379         return chars;
380     }
381 
382     /**
383      * Copies part of the builder's character array into a new character array.
384      *
385      * @param startIndex  the start index, inclusive, must be valid
386      * @param endIndex  the end index, exclusive, must be valid except that
387      *  if too large it is treated as end of string
388      * @return a new array that holds part of the contents of the builder
389      * @throws IndexOutOfBoundsException if startIndex is invalid,
390      *  or if endIndex is invalid (but endIndex greater than size is valid)
391      */
392     public char[] toCharArray(final int startIndex, int endIndex) {
393         endIndex = validateRange(startIndex, endIndex);
394         final int len = endIndex - startIndex;
395         if (len == 0) {
396             return ArrayUtils.EMPTY_CHAR_ARRAY;
397         }
398         final char[] chars = new char[len];
399         System.arraycopy(buffer, startIndex, chars, 0, len);
400         return chars;
401     }
402 
403     /**
404      * Copies the character array into the specified array.
405      *
406      * @param destination  the destination array, null will cause an array to be created
407      * @return the input array, unless that was null or too small
408      */
409     public char[] getChars(char[] destination) {
410         final int len = length();
411         if (destination == null || destination.length < len) {
412             destination = new char[len];
413         }
414         System.arraycopy(buffer, 0, destination, 0, len);
415         return destination;
416     }
417 
418     /**
419      * Copies the character array into the specified array.
420      *
421      * @param startIndex  first index to copy, inclusive, must be valid
422      * @param endIndex  last index, exclusive, must be valid
423      * @param destination  the destination array, must not be null or too small
424      * @param destinationIndex  the index to start copying in destination
425      * @throws NullPointerException if the array is null
426      * @throws IndexOutOfBoundsException if any index is invalid
427      */
428     public void getChars(final int startIndex, final int endIndex, final char[] destination, final int destinationIndex) {
429         if (startIndex < 0) {
430             throw new StringIndexOutOfBoundsException(startIndex);
431         }
432         if (endIndex < 0 || endIndex > length()) {
433             throw new StringIndexOutOfBoundsException(endIndex);
434         }
435         if (startIndex > endIndex) {
436             throw new StringIndexOutOfBoundsException("end < start");
437         }
438         System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
439     }
440 
441     //-----------------------------------------------------------------------
442     /**
443      * If possible, reads chars from the provided {@link Readable} directly into underlying
444      * character buffer without making extra copies.
445      *
446      * @param readable  object to read from
447      * @return the number of characters read
448      * @throws IOException if an I/O error occurs.
449      *
450      * @since 3.4
451      * @see #appendTo(Appendable)
452      */
453     public int readFrom(final Readable readable) throws IOException {
454         final int oldSize = size;
455         if (readable instanceof Reader) {
456             final Reader r = (Reader) readable;
457             ensureCapacity(size + 1);
458             int read;
459             while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
460                 size += read;
461                 ensureCapacity(size + 1);
462             }
463         } else if (readable instanceof CharBuffer) {
464             final CharBuffer cb = (CharBuffer) readable;
465             final int remaining = cb.remaining();
466             ensureCapacity(size + remaining);
467             cb.get(buffer, size, remaining);
468             size += remaining;
469         } else {
470             while (true) {
471                 ensureCapacity(size + 1);
472                 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
473                 final int read = readable.read(buf);
474                 if (read == -1) {
475                     break;
476                 }
477                 size += read;
478             }
479         }
480         return size - oldSize;
481     }
482 
483     //-----------------------------------------------------------------------
484     /**
485      * Appends the new line string to this string builder.
486      * <p>
487      * The new line string can be altered using {@link #setNewLineText(String)}.
488      * This might be used to force the output to always use Unix line endings
489      * even when on Windows.
490      *
491      * @return this, to enable chaining
492      */
493     public StrBuilder appendNewLine() {
494         if (newLine == null)  {
495             append(System.lineSeparator());
496             return this;
497         }
498         return append(newLine);
499     }
500 
501     /**
502      * Appends the text representing {@code null} to this string builder.
503      *
504      * @return this, to enable chaining
505      */
506     public StrBuilder appendNull() {
507         if (nullText == null)  {
508             return this;
509         }
510         return append(nullText);
511     }
512 
513     /**
514      * Appends an object to this string builder.
515      * Appending null will call {@link #appendNull()}.
516      *
517      * @param obj  the object to append
518      * @return this, to enable chaining
519      */
520     public StrBuilder append(final Object obj) {
521         if (obj == null) {
522             return appendNull();
523         }
524         if (obj instanceof CharSequence) {
525             return append((CharSequence) obj);
526         }
527         return append(obj.toString());
528     }
529 
530     /**
531      * Appends a CharSequence to this string builder.
532      * Appending null will call {@link #appendNull()}.
533      *
534      * @param seq  the CharSequence to append
535      * @return this, to enable chaining
536      * @since 3.0
537      */
538     @Override
539     public StrBuilder append(final CharSequence seq) {
540         if (seq == null) {
541             return appendNull();
542         }
543         if (seq instanceof StrBuilder) {
544             return append((StrBuilder) seq);
545         }
546         if (seq instanceof StringBuilder) {
547             return append((StringBuilder) seq);
548         }
549         if (seq instanceof StringBuffer) {
550             return append((StringBuffer) seq);
551         }
552         if (seq instanceof CharBuffer) {
553             return append((CharBuffer) seq);
554         }
555         return append(seq.toString());
556     }
557 
558     /**
559      * Appends part of a CharSequence to this string builder.
560      * Appending null will call {@link #appendNull()}.
561      *
562      * @param seq  the CharSequence to append
563      * @param startIndex  the start index, inclusive, must be valid
564      * @param length  the length to append, must be valid
565      * @return this, to enable chaining
566      * @since 3.0
567      */
568     @Override
569     public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
570         if (seq == null) {
571             return appendNull();
572         }
573         return append(seq.toString(), startIndex, length);
574     }
575 
576     /**
577      * Appends a string to this string builder.
578      * Appending null will call {@link #appendNull()}.
579      *
580      * @param str  the string to append
581      * @return this, to enable chaining
582      */
583     public StrBuilder append(final String str) {
584         if (str == null) {
585             return appendNull();
586         }
587         final int strLen = str.length();
588         if (strLen > 0) {
589             final int len = length();
590             ensureCapacity(len + strLen);
591             str.getChars(0, strLen, buffer, len);
592             size += strLen;
593         }
594         return this;
595     }
596 
597 
598     /**
599      * Appends part of a string to this string builder.
600      * Appending null will call {@link #appendNull()}.
601      *
602      * @param str  the string to append
603      * @param startIndex  the start index, inclusive, must be valid
604      * @param length  the length to append, must be valid
605      * @return this, to enable chaining
606      */
607     public StrBuilder append(final String str, final int startIndex, final int length) {
608         if (str == null) {
609             return appendNull();
610         }
611         if (startIndex < 0 || startIndex > str.length()) {
612             throw new StringIndexOutOfBoundsException("startIndex must be valid");
613         }
614         if (length < 0 || (startIndex + length) > str.length()) {
615             throw new StringIndexOutOfBoundsException("length must be valid");
616         }
617         if (length > 0) {
618             final int len = length();
619             ensureCapacity(len + length);
620             str.getChars(startIndex, startIndex + length, buffer, len);
621             size += length;
622         }
623         return this;
624     }
625 
626     /**
627      * Calls {@link String#format(String, Object...)} and appends the result.
628      *
629      * @param format the format string
630      * @param objs the objects to use in the format string
631      * @return {@code this} to enable chaining
632      * @see String#format(String, Object...)
633      * @since 3.2
634      */
635     public StrBuilder append(final String format, final Object... objs) {
636         return append(String.format(format, objs));
637     }
638 
639     /**
640      * Appends the contents of a char buffer to this string builder.
641      * Appending null will call {@link #appendNull()}.
642      *
643      * @param buf  the char buffer to append
644      * @return this, to enable chaining
645      * @since 3.4
646      */
647     public StrBuilder append(final CharBuffer buf) {
648         if (buf == null) {
649             return appendNull();
650         }
651         if (buf.hasArray()) {
652             final int length = buf.remaining();
653             final int len = length();
654             ensureCapacity(len + length);
655             System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length);
656             size += length;
657         } else {
658             append(buf.toString());
659         }
660         return this;
661     }
662 
663     /**
664      * Appends the contents of a char buffer to this string builder.
665      * Appending null will call {@link #appendNull()}.
666      *
667      * @param buf  the char buffer to append
668      * @param startIndex  the start index, inclusive, must be valid
669      * @param length  the length to append, must be valid
670      * @return this, to enable chaining
671      * @since 3.4
672      */
673     public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
674         if (buf == null) {
675             return appendNull();
676         }
677         if (buf.hasArray()) {
678             final int totalLength = buf.remaining();
679             if (startIndex < 0 || startIndex > totalLength) {
680                 throw new StringIndexOutOfBoundsException("startIndex must be valid");
681             }
682             if (length < 0 || (startIndex + length) > totalLength) {
683                 throw new StringIndexOutOfBoundsException("length must be valid");
684             }
685             final int len = length();
686             ensureCapacity(len + length);
687             System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
688             size += length;
689         } else {
690             append(buf.toString(), startIndex, length);
691         }
692         return this;
693     }
694 
695     /**
696      * Appends a string buffer to this string builder.
697      * Appending null will call {@link #appendNull()}.
698      *
699      * @param str  the string buffer to append
700      * @return this, to enable chaining
701      */
702     public StrBuilder append(final StringBuffer str) {
703         if (str == null) {
704             return appendNull();
705         }
706         final int strLen = str.length();
707         if (strLen > 0) {
708             final int len = length();
709             ensureCapacity(len + strLen);
710             str.getChars(0, strLen, buffer, len);
711             size += strLen;
712         }
713         return this;
714     }
715 
716     /**
717      * Appends part of a string buffer to this string builder.
718      * Appending null will call {@link #appendNull()}.
719      *
720      * @param str  the string to append
721      * @param startIndex  the start index, inclusive, must be valid
722      * @param length  the length to append, must be valid
723      * @return this, to enable chaining
724      */
725     public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
726         if (str == null) {
727             return appendNull();
728         }
729         if (startIndex < 0 || startIndex > str.length()) {
730             throw new StringIndexOutOfBoundsException("startIndex must be valid");
731         }
732         if (length < 0 || (startIndex + length) > str.length()) {
733             throw new StringIndexOutOfBoundsException("length must be valid");
734         }
735         if (length > 0) {
736             final int len = length();
737             ensureCapacity(len + length);
738             str.getChars(startIndex, startIndex + length, buffer, len);
739             size += length;
740         }
741         return this;
742     }
743 
744     /**
745      * Appends a StringBuilder to this string builder.
746      * Appending null will call {@link #appendNull()}.
747      *
748      * @param str the StringBuilder to append
749      * @return this, to enable chaining
750      * @since 3.2
751      */
752     public StrBuilder append(final StringBuilder str) {
753         if (str == null) {
754             return appendNull();
755         }
756         final int strLen = str.length();
757         if (strLen > 0) {
758             final int len = length();
759             ensureCapacity(len + strLen);
760             str.getChars(0, strLen, buffer, len);
761             size += strLen;
762         }
763         return this;
764     }
765 
766     /**
767      * Appends part of a StringBuilder to this string builder.
768      * Appending null will call {@link #appendNull()}.
769      *
770      * @param str the StringBuilder to append
771      * @param startIndex the start index, inclusive, must be valid
772      * @param length the length to append, must be valid
773      * @return this, to enable chaining
774      * @since 3.2
775      */
776     public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
777         if (str == null) {
778             return appendNull();
779         }
780         if (startIndex < 0 || startIndex > str.length()) {
781             throw new StringIndexOutOfBoundsException("startIndex must be valid");
782         }
783         if (length < 0 || (startIndex + length) > str.length()) {
784             throw new StringIndexOutOfBoundsException("length must be valid");
785         }
786         if (length > 0) {
787             final int len = length();
788             ensureCapacity(len + length);
789             str.getChars(startIndex, startIndex + length, buffer, len);
790             size += length;
791         }
792         return this;
793     }
794 
795     /**
796      * Appends another string builder to this string builder.
797      * Appending null will call {@link #appendNull()}.
798      *
799      * @param str  the string builder to append
800      * @return this, to enable chaining
801      */
802     public StrBuilder/StrBuilder.html#StrBuilder">StrBuilder append(final StrBuilder str) {
803         if (str == null) {
804             return appendNull();
805         }
806         final int strLen = str.length();
807         if (strLen > 0) {
808             final int len = length();
809             ensureCapacity(len + strLen);
810             System.arraycopy(str.buffer, 0, buffer, len, strLen);
811             size += strLen;
812         }
813         return this;
814     }
815 
816     /**
817      * Appends part of a string builder to this string builder.
818      * Appending null will call {@link #appendNull()}.
819      *
820      * @param str  the string to append
821      * @param startIndex  the start index, inclusive, must be valid
822      * @param length  the length to append, must be valid
823      * @return this, to enable chaining
824      */
825     public StrBuilder/StrBuilder.html#StrBuilder">StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
826         if (str == null) {
827             return appendNull();
828         }
829         if (startIndex < 0 || startIndex > str.length()) {
830             throw new StringIndexOutOfBoundsException("startIndex must be valid");
831         }
832         if (length < 0 || (startIndex + length) > str.length()) {
833             throw new StringIndexOutOfBoundsException("length must be valid");
834         }
835         if (length > 0) {
836             final int len = length();
837             ensureCapacity(len + length);
838             str.getChars(startIndex, startIndex + length, buffer, len);
839             size += length;
840         }
841         return this;
842     }
843 
844     /**
845      * Appends a char array to the string builder.
846      * Appending null will call {@link #appendNull()}.
847      *
848      * @param chars  the char array to append
849      * @return this, to enable chaining
850      */
851     public StrBuilder append(final char[] chars) {
852         if (chars == null) {
853             return appendNull();
854         }
855         final int strLen = chars.length;
856         if (strLen > 0) {
857             final int len = length();
858             ensureCapacity(len + strLen);
859             System.arraycopy(chars, 0, buffer, len, strLen);
860             size += strLen;
861         }
862         return this;
863     }
864 
865     /**
866      * Appends a char array to the string builder.
867      * Appending null will call {@link #appendNull()}.
868      *
869      * @param chars  the char array to append
870      * @param startIndex  the start index, inclusive, must be valid
871      * @param length  the length to append, must be valid
872      * @return this, to enable chaining
873      */
874     public StrBuilder append(final char[] chars, final int startIndex, final int length) {
875         if (chars == null) {
876             return appendNull();
877         }
878         if (startIndex < 0 || startIndex > chars.length) {
879             throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
880         }
881         if (length < 0 || (startIndex + length) > chars.length) {
882             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
883         }
884         if (length > 0) {
885             final int len = length();
886             ensureCapacity(len + length);
887             System.arraycopy(chars, startIndex, buffer, len, length);
888             size += length;
889         }
890         return this;
891     }
892 
893     /**
894      * Appends a boolean value to the string builder.
895      *
896      * @param value  the value to append
897      * @return this, to enable chaining
898      */
899     public StrBuilder append(final boolean value) {
900         if (value) {
901             ensureCapacity(size + 4);
902             buffer[size++] = 't';
903             buffer[size++] = 'r';
904             buffer[size++] = 'u';
905             buffer[size++] = 'e';
906         } else {
907             ensureCapacity(size + 5);
908             buffer[size++] = 'f';
909             buffer[size++] = 'a';
910             buffer[size++] = 'l';
911             buffer[size++] = 's';
912             buffer[size++] = 'e';
913         }
914         return this;
915     }
916 
917     /**
918      * Appends a char value to the string builder.
919      *
920      * @param ch  the value to append
921      * @return this, to enable chaining
922      * @since 3.0
923      */
924     @Override
925     public StrBuilder append(final char ch) {
926         final int len = length();
927         ensureCapacity(len + 1);
928         buffer[size++] = ch;
929         return this;
930     }
931 
932     /**
933      * Appends an int value to the string builder using {@code String.valueOf}.
934      *
935      * @param value  the value to append
936      * @return this, to enable chaining
937      */
938     public StrBuilder append(final int value) {
939         return append(String.valueOf(value));
940     }
941 
942     /**
943      * Appends a long value to the string builder using {@code String.valueOf}.
944      *
945      * @param value  the value to append
946      * @return this, to enable chaining
947      */
948     public StrBuilder append(final long value) {
949         return append(String.valueOf(value));
950     }
951 
952     /**
953      * Appends a float value to the string builder using {@code String.valueOf}.
954      *
955      * @param value  the value to append
956      * @return this, to enable chaining
957      */
958     public StrBuilder append(final float value) {
959         return append(String.valueOf(value));
960     }
961 
962     /**
963      * Appends a double value to the string builder using {@code String.valueOf}.
964      *
965      * @param value  the value to append
966      * @return this, to enable chaining
967      */
968     public StrBuilder append(final double value) {
969         return append(String.valueOf(value));
970     }
971 
972     //-----------------------------------------------------------------------
973     /**
974      * Appends an object followed by a new line to this string builder.
975      * Appending null will call {@link #appendNull()}.
976      *
977      * @param obj  the object to append
978      * @return this, to enable chaining
979      * @since 2.3
980      */
981     public StrBuilder appendln(final Object obj) {
982         return append(obj).appendNewLine();
983     }
984 
985     /**
986      * Appends a string followed by a new line to this string builder.
987      * Appending null will call {@link #appendNull()}.
988      *
989      * @param str  the string to append
990      * @return this, to enable chaining
991      * @since 2.3
992      */
993     public StrBuilder appendln(final String str) {
994         return append(str).appendNewLine();
995     }
996 
997     /**
998      * Appends part of a string followed by a new line to this string builder.
999      * Appending null will call {@link #appendNull()}.
1000      *
1001      * @param str  the string to append
1002      * @param startIndex  the start index, inclusive, must be valid
1003      * @param length  the length to append, must be valid
1004      * @return this, to enable chaining
1005      * @since 2.3
1006      */
1007     public StrBuilder appendln(final String str, final int startIndex, final int length) {
1008         return append(str, startIndex, length).appendNewLine();
1009     }
1010 
1011     /**
1012      * Calls {@link String#format(String, Object...)} and appends the result.
1013      *
1014      * @param format the format string
1015      * @param objs the objects to use in the format string
1016      * @return {@code this} to enable chaining
1017      * @see String#format(String, Object...)
1018      * @since 3.2
1019      */
1020     public StrBuilder appendln(final String format, final Object... objs) {
1021         return append(format, objs).appendNewLine();
1022     }
1023 
1024     /**
1025      * Appends a string buffer followed by a new line to this string builder.
1026      * Appending null will call {@link #appendNull()}.
1027      *
1028      * @param str  the string buffer to append
1029      * @return this, to enable chaining
1030      * @since 2.3
1031      */
1032     public StrBuilder appendln(final StringBuffer str) {
1033         return append(str).appendNewLine();
1034     }
1035 
1036     /**
1037      * Appends a string builder followed by a new line to this string builder.
1038      * Appending null will call {@link #appendNull()}.
1039      *
1040      * @param str  the string builder to append
1041      * @return this, to enable chaining
1042      * @since 3.2
1043      */
1044     public StrBuilder appendln(final StringBuilder str) {
1045         return append(str).appendNewLine();
1046     }
1047 
1048     /**
1049      * Appends part of a string builder followed by a new line to this string builder.
1050      * Appending null will call {@link #appendNull()}.
1051      *
1052      * @param str  the string builder to append
1053      * @param startIndex  the start index, inclusive, must be valid
1054      * @param length  the length to append, must be valid
1055      * @return this, to enable chaining
1056      * @since 3.2
1057      */
1058     public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
1059         return append(str, startIndex, length).appendNewLine();
1060     }
1061 
1062     /**
1063      * Appends part of a string buffer followed by a new line to this string builder.
1064      * Appending null will call {@link #appendNull()}.
1065      *
1066      * @param str  the string to append
1067      * @param startIndex  the start index, inclusive, must be valid
1068      * @param length  the length to append, must be valid
1069      * @return this, to enable chaining
1070      * @since 2.3
1071      */
1072     public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
1073         return append(str, startIndex, length).appendNewLine();
1074     }
1075 
1076     /**
1077      * Appends another string builder followed by a new line to this string builder.
1078      * Appending null will call {@link #appendNull()}.
1079      *
1080      * @param str  the string builder to append
1081      * @return this, to enable chaining
1082      * @since 2.3
1083      */
1084     public StrBuildertrBuilder.html#StrBuilder">StrBuilder appendln(final StrBuilder str) {
1085         return append(str).appendNewLine();
1086     }
1087 
1088     /**
1089      * Appends part of a string builder followed by a new line to this string builder.
1090      * Appending null will call {@link #appendNull()}.
1091      *
1092      * @param str  the string to append
1093      * @param startIndex  the start index, inclusive, must be valid
1094      * @param length  the length to append, must be valid
1095      * @return this, to enable chaining
1096      * @since 2.3
1097      */
1098     public StrBuildertrBuilder.html#StrBuilder">StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
1099         return append(str, startIndex, length).appendNewLine();
1100     }
1101 
1102     /**
1103      * Appends a char array followed by a new line to the string builder.
1104      * Appending null will call {@link #appendNull()}.
1105      *
1106      * @param chars  the char array to append
1107      * @return this, to enable chaining
1108      * @since 2.3
1109      */
1110     public StrBuilder appendln(final char[] chars) {
1111         return append(chars).appendNewLine();
1112     }
1113 
1114     /**
1115      * Appends a char array followed by a new line to the string builder.
1116      * Appending null will call {@link #appendNull()}.
1117      *
1118      * @param chars  the char array to append
1119      * @param startIndex  the start index, inclusive, must be valid
1120      * @param length  the length to append, must be valid
1121      * @return this, to enable chaining
1122      * @since 2.3
1123      */
1124     public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
1125         return append(chars, startIndex, length).appendNewLine();
1126     }
1127 
1128     /**
1129      * Appends a boolean value followed by a new line to the string builder.
1130      *
1131      * @param value  the value to append
1132      * @return this, to enable chaining
1133      * @since 2.3
1134      */
1135     public StrBuilder appendln(final boolean value) {
1136         return append(value).appendNewLine();
1137     }
1138 
1139     /**
1140      * Appends a char value followed by a new line to the string builder.
1141      *
1142      * @param ch  the value to append
1143      * @return this, to enable chaining
1144      * @since 2.3
1145      */
1146     public StrBuilder appendln(final char ch) {
1147         return append(ch).appendNewLine();
1148     }
1149 
1150     /**
1151      * Appends an int value followed by a new line to the string builder using {@code String.valueOf}.
1152      *
1153      * @param value  the value to append
1154      * @return this, to enable chaining
1155      * @since 2.3
1156      */
1157     public StrBuilder appendln(final int value) {
1158         return append(value).appendNewLine();
1159     }
1160 
1161     /**
1162      * Appends a long value followed by a new line to the string builder using {@code String.valueOf}.
1163      *
1164      * @param value  the value to append
1165      * @return this, to enable chaining
1166      * @since 2.3
1167      */
1168     public StrBuilder appendln(final long value) {
1169         return append(value).appendNewLine();
1170     }
1171 
1172     /**
1173      * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
1174      *
1175      * @param value  the value to append
1176      * @return this, to enable chaining
1177      * @since 2.3
1178      */
1179     public StrBuilder appendln(final float value) {
1180         return append(value).appendNewLine();
1181     }
1182 
1183     /**
1184      * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
1185      *
1186      * @param value  the value to append
1187      * @return this, to enable chaining
1188      * @since 2.3
1189      */
1190     public StrBuilder appendln(final double value) {
1191         return append(value).appendNewLine();
1192     }
1193 
1194     //-----------------------------------------------------------------------
1195     /**
1196      * Appends each item in an array to the builder without any separators.
1197      * Appending a null array will have no effect.
1198      * Each object is appended using {@link #append(Object)}.
1199      *
1200      * @param <T>  the element type
1201      * @param array  the array to append
1202      * @return this, to enable chaining
1203      * @since 2.3
1204      */
1205     public <T> StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
1206         /*
1207          * @SuppressWarnings used to hide warning about vararg usage. We cannot
1208          * use @SafeVarargs, since this method is not final. Using @SuppressWarnings
1209          * is fine, because it isn't inherited by subclasses, so each subclass must
1210          * vouch for itself whether its use of 'array' is safe.
1211          */
1212         if (ArrayUtils.isNotEmpty(array)) {
1213             for (final Object element : array) {
1214                 append(element);
1215             }
1216         }
1217         return this;
1218     }
1219 
1220     /**
1221      * Appends each item in an iterable to the builder without any separators.
1222      * Appending a null iterable will have no effect.
1223      * Each object is appended using {@link #append(Object)}.
1224      *
1225      * @param iterable  the iterable to append
1226      * @return this, to enable chaining
1227      * @since 2.3
1228      */
1229     public StrBuilder appendAll(final Iterable<?> iterable) {
1230         if (iterable != null) {
1231             for (final Object o : iterable) {
1232                 append(o);
1233             }
1234         }
1235         return this;
1236     }
1237 
1238     /**
1239      * Appends each item in an iterator to the builder without any separators.
1240      * Appending a null iterator will have no effect.
1241      * Each object is appended using {@link #append(Object)}.
1242      *
1243      * @param it  the iterator to append
1244      * @return this, to enable chaining
1245      * @since 2.3
1246      */
1247     public StrBuilder appendAll(final Iterator<?> it) {
1248         if (it != null) {
1249             while (it.hasNext()) {
1250                 append(it.next());
1251             }
1252         }
1253         return this;
1254     }
1255 
1256     //-----------------------------------------------------------------------
1257     /**
1258      * Appends an array placing separators between each value, but
1259      * not before the first or after the last.
1260      * Appending a null array will have no effect.
1261      * Each object is appended using {@link #append(Object)}.
1262      *
1263      * @param array  the array to append
1264      * @param separator  the separator to use, null means no separator
1265      * @return this, to enable chaining
1266      */
1267     public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
1268         if (array != null && array.length > 0) {
1269             final String sep = Objects.toString(separator, "");
1270             append(array[0]);
1271             for (int i = 1; i < array.length; i++) {
1272                 append(sep);
1273                 append(array[i]);
1274             }
1275         }
1276         return this;
1277     }
1278 
1279     /**
1280      * Appends an iterable placing separators between each value, but
1281      * not before the first or after the last.
1282      * Appending a null iterable will have no effect.
1283      * Each object is appended using {@link #append(Object)}.
1284      *
1285      * @param iterable  the iterable to append
1286      * @param separator  the separator to use, null means no separator
1287      * @return this, to enable chaining
1288      */
1289     public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1290         if (iterable != null) {
1291             final String sep = Objects.toString(separator, "");
1292             final Iterator<?> it = iterable.iterator();
1293             while (it.hasNext()) {
1294                 append(it.next());
1295                 if (it.hasNext()) {
1296                     append(sep);
1297                 }
1298             }
1299         }
1300         return this;
1301     }
1302 
1303     /**
1304      * Appends an iterator placing separators between each value, but
1305      * not before the first or after the last.
1306      * Appending a null iterator will have no effect.
1307      * Each object is appended using {@link #append(Object)}.
1308      *
1309      * @param it  the iterator to append
1310      * @param separator  the separator to use, null means no separator
1311      * @return this, to enable chaining
1312      */
1313     public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
1314         if (it != null) {
1315             final String sep = Objects.toString(separator, "");
1316             while (it.hasNext()) {
1317                 append(it.next());
1318                 if (it.hasNext()) {
1319                     append(sep);
1320                 }
1321             }
1322         }
1323         return this;
1324     }
1325 
1326     //-----------------------------------------------------------------------
1327     /**
1328      * Appends a separator if the builder is currently non-empty.
1329      * Appending a null separator will have no effect.
1330      * The separator is appended using {@link #append(String)}.
1331      * <p>
1332      * This method is useful for adding a separator each time around the
1333      * loop except the first.
1334      * <pre>
1335      * for (Iterator it = list.iterator(); it.hasNext(); ) {
1336      *   appendSeparator(",");
1337      *   append(it.next());
1338      * }
1339      * </pre>
1340      * Note that for this simple example, you should use
1341      * {@link #appendWithSeparators(Iterable, String)}.
1342      *
1343      * @param separator  the separator to use, null means no separator
1344      * @return this, to enable chaining
1345      * @since 2.3
1346      */
1347     public StrBuilder appendSeparator(final String separator) {
1348         return appendSeparator(separator, null);
1349     }
1350 
1351     /**
1352      * Appends one of both separators to the StrBuilder.
1353      * If the builder is currently empty it will append the defaultIfEmpty-separator
1354      * Otherwise it will append the standard-separator
1355      *
1356      * Appending a null separator will have no effect.
1357      * The separator is appended using {@link #append(String)}.
1358      * <p>
1359      * This method is for example useful for constructing queries
1360      * <pre>
1361      * StrBuilder whereClause = new StrBuilder();
1362      * if (searchCommand.getPriority() != null) {
1363      *  whereClause.appendSeparator(" and", " where");
1364      *  whereClause.append(" priority = ?")
1365      * }
1366      * if (searchCommand.getComponent() != null) {
1367      *  whereClause.appendSeparator(" and", " where");
1368      *  whereClause.append(" component = ?")
1369      * }
1370      * selectClause.append(whereClause)
1371      * </pre>
1372      *
1373      * @param standard the separator if builder is not empty, null means no separator
1374      * @param defaultIfEmpty the separator if builder is empty, null means no separator
1375      * @return this, to enable chaining
1376      * @since 2.5
1377      */
1378     public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1379         final String str = isEmpty() ? defaultIfEmpty : standard;
1380         if (str != null) {
1381             append(str);
1382         }
1383         return this;
1384     }
1385 
1386     /**
1387      * Appends a separator if the builder is currently non-empty.
1388      * The separator is appended using {@link #append(char)}.
1389      * <p>
1390      * This method is useful for adding a separator each time around the
1391      * loop except the first.
1392      * <pre>
1393      * for (Iterator it = list.iterator(); it.hasNext(); ) {
1394      *   appendSeparator(',');
1395      *   append(it.next());
1396      * }
1397      * </pre>
1398      * Note that for this simple example, you should use
1399      * {@link #appendWithSeparators(Iterable, String)}.
1400      *
1401      * @param separator  the separator to use
1402      * @return this, to enable chaining
1403      * @since 2.3
1404      */
1405     public StrBuilder appendSeparator(final char separator) {
1406         if (isNotEmpty()) {
1407             append(separator);
1408         }
1409         return this;
1410     }
1411 
1412     /**
1413      * Append one of both separators to the builder
1414      * If the builder is currently empty it will append the defaultIfEmpty-separator
1415      * Otherwise it will append the standard-separator
1416      *
1417      * The separator is appended using {@link #append(char)}.
1418      * @param standard the separator if builder is not empty
1419      * @param defaultIfEmpty the separator if builder is empty
1420      * @return this, to enable chaining
1421      * @since 2.5
1422      */
1423     public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1424         if (isNotEmpty()) {
1425             append(standard);
1426         } else {
1427             append(defaultIfEmpty);
1428         }
1429         return this;
1430     }
1431     /**
1432      * Appends a separator to the builder if the loop index is greater than zero.
1433      * Appending a null separator will have no effect.
1434      * The separator is appended using {@link #append(String)}.
1435      * <p>
1436      * This method is useful for adding a separator each time around the
1437      * loop except the first.
1438      * </p>
1439      * <pre>
1440      * for (int i = 0; i &lt; list.size(); i++) {
1441      *   appendSeparator(",", i);
1442      *   append(list.get(i));
1443      * }
1444      * </pre>
1445      * Note that for this simple example, you should use
1446      * {@link #appendWithSeparators(Iterable, String)}.
1447      *
1448      * @param separator  the separator to use, null means no separator
1449      * @param loopIndex  the loop index
1450      * @return this, to enable chaining
1451      * @since 2.3
1452      */
1453     public StrBuilder appendSeparator(final String separator, final int loopIndex) {
1454         if (separator != null && loopIndex > 0) {
1455             append(separator);
1456         }
1457         return this;
1458     }
1459 
1460     /**
1461      * Appends a separator to the builder if the loop index is greater than zero.
1462      * The separator is appended using {@link #append(char)}.
1463      * <p>
1464      * This method is useful for adding a separator each time around the
1465      * loop except the first.
1466      * </p>
1467      * <pre>
1468      * for (int i = 0; i &lt; list.size(); i++) {
1469      *   appendSeparator(",", i);
1470      *   append(list.get(i));
1471      * }
1472      * </pre>
1473      * Note that for this simple example, you should use
1474      * {@link #appendWithSeparators(Iterable, String)}.
1475      *
1476      * @param separator  the separator to use
1477      * @param loopIndex  the loop index
1478      * @return this, to enable chaining
1479      * @since 2.3
1480      */
1481     public StrBuilder appendSeparator(final char separator, final int loopIndex) {
1482         if (loopIndex > 0) {
1483             append(separator);
1484         }
1485         return this;
1486     }
1487 
1488     //-----------------------------------------------------------------------
1489     /**
1490      * Appends the pad character to the builder the specified number of times.
1491      *
1492      * @param length  the length to append, negative means no append
1493      * @param padChar  the character to append
1494      * @return this, to enable chaining
1495      */
1496     public StrBuilder appendPadding(final int length, final char padChar) {
1497         if (length >= 0) {
1498             ensureCapacity(size + length);
1499             for (int i = 0; i < length; i++) {
1500                 buffer[size++] = padChar;
1501             }
1502         }
1503         return this;
1504     }
1505 
1506     //-----------------------------------------------------------------------
1507     /**
1508      * Appends an object to the builder padding on the left to a fixed width.
1509      * The {@code toString} of the object is used.
1510      * If the object is larger than the length, the left hand side is lost.
1511      * If the object is null, the null text value is used.
1512      *
1513      * @param obj  the object to append, null uses null text
1514      * @param width  the fixed field width, zero or negative has no effect
1515      * @param padChar  the pad character to use
1516      * @return this, to enable chaining
1517      */
1518     public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
1519         if (width > 0) {
1520             ensureCapacity(size + width);
1521             String str = (obj == null ? getNullText() : obj.toString());
1522             if (str == null) {
1523                 str = StringUtils.EMPTY;
1524             }
1525             final int strLen = str.length();
1526             if (strLen >= width) {
1527                 str.getChars(strLen - width, strLen, buffer, size);
1528             } else {
1529                 final int padLen = width - strLen;
1530                 for (int i = 0; i < padLen; i++) {
1531                     buffer[size + i] = padChar;
1532                 }
1533                 str.getChars(0, strLen, buffer, size + padLen);
1534             }
1535             size += width;
1536         }
1537         return this;
1538     }
1539 
1540     /**
1541      * Appends an object to the builder padding on the left to a fixed width.
1542      * The {@code String.valueOf} of the {@code int} value is used.
1543      * If the formatted value is larger than the length, the left hand side is lost.
1544      *
1545      * @param value  the value to append
1546      * @param width  the fixed field width, zero or negative has no effect
1547      * @param padChar  the pad character to use
1548      * @return this, to enable chaining
1549      */
1550     public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
1551         return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
1552     }
1553 
1554     /**
1555      * Appends an object to the builder padding on the right to a fixed length.
1556      * The {@code toString} of the object is used.
1557      * If the object is larger than the length, the right hand side is lost.
1558      * If the object is null, null text value is used.
1559      *
1560      * @param obj  the object to append, null uses null text
1561      * @param width  the fixed field width, zero or negative has no effect
1562      * @param padChar  the pad character to use
1563      * @return this, to enable chaining
1564      */
1565     public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
1566         if (width > 0) {
1567             ensureCapacity(size + width);
1568             String str = (obj == null ? getNullText() : obj.toString());
1569             if (str == null) {
1570                 str = StringUtils.EMPTY;
1571             }
1572             final int strLen = str.length();
1573             if (strLen >= width) {
1574                 str.getChars(0, width, buffer, size);
1575             } else {
1576                 final int padLen = width - strLen;
1577                 str.getChars(0, strLen, buffer, size);
1578                 for (int i = 0; i < padLen; i++) {
1579                     buffer[size + strLen + i] = padChar;
1580                 }
1581             }
1582             size += width;
1583         }
1584         return this;
1585     }
1586 
1587     /**
1588      * Appends an object to the builder padding on the right to a fixed length.
1589      * The {@code String.valueOf} of the {@code int} value is used.
1590      * If the object is larger than the length, the right hand side is lost.
1591      *
1592      * @param value  the value to append
1593      * @param width  the fixed field width, zero or negative has no effect
1594      * @param padChar  the pad character to use
1595      * @return this, to enable chaining
1596      */
1597     public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
1598         return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
1599     }
1600 
1601     //-----------------------------------------------------------------------
1602     /**
1603      * Inserts the string representation of an object into this builder.
1604      * Inserting null will use the stored null text value.
1605      *
1606      * @param index  the index to add at, must be valid
1607      * @param obj  the object to insert
1608      * @return this, to enable chaining
1609      * @throws IndexOutOfBoundsException if the index is invalid
1610      */
1611     public StrBuilder insert(final int index, final Object obj) {
1612         if (obj == null) {
1613             return insert(index, nullText);
1614         }
1615         return insert(index, obj.toString());
1616     }
1617 
1618     /**
1619      * Inserts the string into this builder.
1620      * Inserting null will use the stored null text value.
1621      *
1622      * @param index  the index to add at, must be valid
1623      * @param str  the string to insert
1624      * @return this, to enable chaining
1625      * @throws IndexOutOfBoundsException if the index is invalid
1626      */
1627     public StrBuilder insert(final int index, String str) {
1628         validateIndex(index);
1629         if (str == null) {
1630             str = nullText;
1631         }
1632         if (str != null) {
1633             final int strLen = str.length();
1634             if (strLen > 0) {
1635                 final int newSize = size + strLen;
1636                 ensureCapacity(newSize);
1637                 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
1638                 size = newSize;
1639                 str.getChars(0, strLen, buffer, index);
1640             }
1641         }
1642         return this;
1643     }
1644 
1645     /**
1646      * Inserts the character array into this builder.
1647      * Inserting null will use the stored null text value.
1648      *
1649      * @param index  the index to add at, must be valid
1650      * @param chars  the char array to insert
1651      * @return this, to enable chaining
1652      * @throws IndexOutOfBoundsException if the index is invalid
1653      */
1654     public StrBuilder insert(final int index, final char[] chars) {
1655         validateIndex(index);
1656         if (chars == null) {
1657             return insert(index, nullText);
1658         }
1659         final int len = chars.length;
1660         if (len > 0) {
1661             ensureCapacity(size + len);
1662             System.arraycopy(buffer, index, buffer, index + len, size - index);
1663             System.arraycopy(chars, 0, buffer, index, len);
1664             size += len;
1665         }
1666         return this;
1667     }
1668 
1669     /**
1670      * Inserts part of the character array into this builder.
1671      * Inserting null will use the stored null text value.
1672      *
1673      * @param index  the index to add at, must be valid
1674      * @param chars  the char array to insert
1675      * @param offset  the offset into the character array to start at, must be valid
1676      * @param length  the length of the character array part to copy, must be positive
1677      * @return this, to enable chaining
1678      * @throws IndexOutOfBoundsException if any index is invalid
1679      */
1680     public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
1681         validateIndex(index);
1682         if (chars == null) {
1683             return insert(index, nullText);
1684         }
1685         if (offset < 0 || offset > chars.length) {
1686             throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
1687         }
1688         if (length < 0 || offset + length > chars.length) {
1689             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
1690         }
1691         if (length > 0) {
1692             ensureCapacity(size + length);
1693             System.arraycopy(buffer, index, buffer, index + length, size - index);
1694             System.arraycopy(chars, offset, buffer, index, length);
1695             size += length;
1696         }
1697         return this;
1698     }
1699 
1700     /**
1701      * Inserts the value into this builder.
1702      *
1703      * @param index  the index to add at, must be valid
1704      * @param value  the value to insert
1705      * @return this, to enable chaining
1706      * @throws IndexOutOfBoundsException if the index is invalid
1707      */
1708     public StrBuilder insert(int index, final boolean value) {
1709         validateIndex(index);
1710         if (value) {
1711             ensureCapacity(size + 4);
1712             System.arraycopy(buffer, index, buffer, index + 4, size - index);
1713             buffer[index++] = 't';
1714             buffer[index++] = 'r';
1715             buffer[index++] = 'u';
1716             buffer[index] = 'e';
1717             size += 4;
1718         } else {
1719             ensureCapacity(size + 5);
1720             System.arraycopy(buffer, index, buffer, index + 5, size - index);
1721             buffer[index++] = 'f';
1722             buffer[index++] = 'a';
1723             buffer[index++] = 'l';
1724             buffer[index++] = 's';
1725             buffer[index] = 'e';
1726             size += 5;
1727         }
1728         return this;
1729     }
1730 
1731     /**
1732      * Inserts the value into this builder.
1733      *
1734      * @param index  the index to add at, must be valid
1735      * @param value  the value to insert
1736      * @return this, to enable chaining
1737      * @throws IndexOutOfBoundsException if the index is invalid
1738      */
1739     public StrBuilder insert(final int index, final char value) {
1740         validateIndex(index);
1741         ensureCapacity(size + 1);
1742         System.arraycopy(buffer, index, buffer, index + 1, size - index);
1743         buffer[index] = value;
1744         size++;
1745         return this;
1746     }
1747 
1748     /**
1749      * Inserts the value into this builder.
1750      *
1751      * @param index  the index to add at, must be valid
1752      * @param value  the value to insert
1753      * @return this, to enable chaining
1754      * @throws IndexOutOfBoundsException if the index is invalid
1755      */
1756     public StrBuilder insert(final int index, final int value) {
1757         return insert(index, String.valueOf(value));
1758     }
1759 
1760     /**
1761      * Inserts the value into this builder.
1762      *
1763      * @param index  the index to add at, must be valid
1764      * @param value  the value to insert
1765      * @return this, to enable chaining
1766      * @throws IndexOutOfBoundsException if the index is invalid
1767      */
1768     public StrBuilder insert(final int index, final long value) {
1769         return insert(index, String.valueOf(value));
1770     }
1771 
1772     /**
1773      * Inserts the value into this builder.
1774      *
1775      * @param index  the index to add at, must be valid
1776      * @param value  the value to insert
1777      * @return this, to enable chaining
1778      * @throws IndexOutOfBoundsException if the index is invalid
1779      */
1780     public StrBuilder insert(final int index, final float value) {
1781         return insert(index, String.valueOf(value));
1782     }
1783 
1784     /**
1785      * Inserts the value into this builder.
1786      *
1787      * @param index  the index to add at, must be valid
1788      * @param value  the value to insert
1789      * @return this, to enable chaining
1790      * @throws IndexOutOfBoundsException if the index is invalid
1791      */
1792     public StrBuilder insert(final int index, final double value) {
1793         return insert(index, String.valueOf(value));
1794     }
1795 
1796     //-----------------------------------------------------------------------
1797     /**
1798      * Internal method to delete a range without validation.
1799      *
1800      * @param startIndex  the start index, must be valid
1801      * @param endIndex  the end index (exclusive), must be valid
1802      * @param len  the length, must be valid
1803      * @throws IndexOutOfBoundsException if any index is invalid
1804      */
1805     private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1806         System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1807         size -= len;
1808     }
1809 
1810     /**
1811      * Deletes the characters between the two specified indices.
1812      *
1813      * @param startIndex  the start index, inclusive, must be valid
1814      * @param endIndex  the end index, exclusive, must be valid except
1815      *  that if too large it is treated as end of string
1816      * @return this, to enable chaining
1817      * @throws IndexOutOfBoundsException if the index is invalid
1818      */
1819     public StrBuilder delete(final int startIndex, int endIndex) {
1820         endIndex = validateRange(startIndex, endIndex);
1821         final int len = endIndex - startIndex;
1822         if (len > 0) {
1823             deleteImpl(startIndex, endIndex, len);
1824         }
1825         return this;
1826     }
1827 
1828     //-----------------------------------------------------------------------
1829     /**
1830      * Deletes the character wherever it occurs in the builder.
1831      *
1832      * @param ch  the character to delete
1833      * @return this, to enable chaining
1834      */
1835     public StrBuilder deleteAll(final char ch) {
1836         for (int i = 0; i < size; i++) {
1837             if (buffer[i] == ch) {
1838                 final int start = i;
1839                 while (++i < size) {
1840                     if (buffer[i] != ch) {
1841                         break;
1842                     }
1843                 }
1844                 final int len = i - start;
1845                 deleteImpl(start, i, len);
1846                 i -= len;
1847             }
1848         }
1849         return this;
1850     }
1851 
1852     /**
1853      * Deletes the character wherever it occurs in the builder.
1854      *
1855      * @param ch  the character to delete
1856      * @return this, to enable chaining
1857      */
1858     public StrBuilder deleteFirst(final char ch) {
1859         for (int i = 0; i < size; i++) {
1860             if (buffer[i] == ch) {
1861                 deleteImpl(i, i + 1, 1);
1862                 break;
1863             }
1864         }
1865         return this;
1866     }
1867 
1868     //-----------------------------------------------------------------------
1869     /**
1870      * Deletes the string wherever it occurs in the builder.
1871      *
1872      * @param str  the string to delete, null causes no action
1873      * @return this, to enable chaining
1874      */
1875     public StrBuilder deleteAll(final String str) {
1876         final int len = (str == null ? 0 : str.length());
1877         if (len > 0) {
1878             int index = indexOf(str, 0);
1879             while (index >= 0) {
1880                 deleteImpl(index, index + len, len);
1881                 index = indexOf(str, index);
1882             }
1883         }
1884         return this;
1885     }
1886 
1887     /**
1888      * Deletes the string wherever it occurs in the builder.
1889      *
1890      * @param str  the string to delete, null causes no action
1891      * @return this, to enable chaining
1892      */
1893     public StrBuilder deleteFirst(final String str) {
1894         final int len = (str == null ? 0 : str.length());
1895         if (len > 0) {
1896             final int index = indexOf(str, 0);
1897             if (index >= 0) {
1898                 deleteImpl(index, index + len, len);
1899             }
1900         }
1901         return this;
1902     }
1903 
1904     //-----------------------------------------------------------------------
1905     /**
1906      * Deletes all parts of the builder that the matcher matches.
1907      * <p>
1908      * Matchers can be used to perform advanced deletion behavior.
1909      * For example you could write a matcher to delete all occurrences
1910      * where the character 'a' is followed by a number.
1911      *
1912      * @param matcher  the matcher to use to find the deletion, null causes no action
1913      * @return this, to enable chaining
1914      */
1915     public StrBuilder deleteAll(final StrMatcher matcher) {
1916         return replace(matcher, null, 0, size, -1);
1917     }
1918 
1919     /**
1920      * Deletes the first match within the builder using the specified matcher.
1921      * <p>
1922      * Matchers can be used to perform advanced deletion behavior.
1923      * For example you could write a matcher to delete
1924      * where the character 'a' is followed by a number.
1925      *
1926      * @param matcher  the matcher to use to find the deletion, null causes no action
1927      * @return this, to enable chaining
1928      */
1929     public StrBuilder deleteFirst(final StrMatcher matcher) {
1930         return replace(matcher, null, 0, size, 1);
1931     }
1932 
1933     //-----------------------------------------------------------------------
1934     /**
1935      * Internal method to delete a range without validation.
1936      *
1937      * @param startIndex  the start index, must be valid
1938      * @param endIndex  the end index (exclusive), must be valid
1939      * @param removeLen  the length to remove (endIndex - startIndex), must be valid
1940      * @param insertStr  the string to replace with, null means delete range
1941      * @param insertLen  the length of the insert string, must be valid
1942      * @throws IndexOutOfBoundsException if any index is invalid
1943      */
1944     private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
1945         final int newSize = size - removeLen + insertLen;
1946         if (insertLen != removeLen) {
1947             ensureCapacity(newSize);
1948             System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
1949             size = newSize;
1950         }
1951         if (insertLen > 0) {
1952             insertStr.getChars(0, insertLen, buffer, startIndex);
1953         }
1954     }
1955 
1956     /**
1957      * Replaces a portion of the string builder with another string.
1958      * The length of the inserted string does not have to match the removed length.
1959      *
1960      * @param startIndex  the start index, inclusive, must be valid
1961      * @param endIndex  the end index, exclusive, must be valid except
1962      *  that if too large it is treated as end of string
1963      * @param replaceStr  the string to replace with, null means delete range
1964      * @return this, to enable chaining
1965      * @throws IndexOutOfBoundsException if the index is invalid
1966      */
1967     public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
1968         endIndex = validateRange(startIndex, endIndex);
1969         final int insertLen = (replaceStr == null ? 0 : replaceStr.length());
1970         replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
1971         return this;
1972     }
1973 
1974     //-----------------------------------------------------------------------
1975     /**
1976      * Replaces the search character with the replace character
1977      * throughout the builder.
1978      *
1979      * @param search  the search character
1980      * @param replace  the replace character
1981      * @return this, to enable chaining
1982      */
1983     public StrBuilder replaceAll(final char search, final char replace) {
1984         if (search != replace) {
1985             for (int i = 0; i < size; i++) {
1986                 if (buffer[i] == search) {
1987                     buffer[i] = replace;
1988                 }
1989             }
1990         }
1991         return this;
1992     }
1993 
1994     /**
1995      * Replaces the first instance of the search character with the
1996      * replace character in the builder.
1997      *
1998      * @param search  the search character
1999      * @param replace  the replace character
2000      * @return this, to enable chaining
2001      */
2002     public StrBuilder replaceFirst(final char search, final char replace) {
2003         if (search != replace) {
2004             for (int i = 0; i < size; i++) {
2005                 if (buffer[i] == search) {
2006                     buffer[i] = replace;
2007                     break;
2008                 }
2009             }
2010         }
2011         return this;
2012     }
2013 
2014     //-----------------------------------------------------------------------
2015     /**
2016      * Replaces the search string with the replace string throughout the builder.
2017      *
2018      * @param searchStr  the search string, null causes no action to occur
2019      * @param replaceStr  the replace string, null is equivalent to an empty string
2020      * @return this, to enable chaining
2021      */
2022     public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
2023         final int searchLen = (searchStr == null ? 0 : searchStr.length());
2024         if (searchLen > 0) {
2025             final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
2026             int index = indexOf(searchStr, 0);
2027             while (index >= 0) {
2028                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2029                 index = indexOf(searchStr, index + replaceLen);
2030             }
2031         }
2032         return this;
2033     }
2034 
2035     /**
2036      * Replaces the first instance of the search string with the replace string.
2037      *
2038      * @param searchStr  the search string, null causes no action to occur
2039      * @param replaceStr  the replace string, null is equivalent to an empty string
2040      * @return this, to enable chaining
2041      */
2042     public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
2043         final int searchLen = (searchStr == null ? 0 : searchStr.length());
2044         if (searchLen > 0) {
2045             final int index = indexOf(searchStr, 0);
2046             if (index >= 0) {
2047                 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
2048                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2049             }
2050         }
2051         return this;
2052     }
2053 
2054     //-----------------------------------------------------------------------
2055     /**
2056      * Replaces all matches within the builder with the replace string.
2057      * <p>
2058      * Matchers can be used to perform advanced replace behavior.
2059      * For example you could write a matcher to replace all occurrences
2060      * where the character 'a' is followed by a number.
2061      *
2062      * @param matcher  the matcher to use to find the deletion, null causes no action
2063      * @param replaceStr  the replace string, null is equivalent to an empty string
2064      * @return this, to enable chaining
2065      */
2066     public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
2067         return replace(matcher, replaceStr, 0, size, -1);
2068     }
2069 
2070     /**
2071      * Replaces the first match within the builder with the replace string.
2072      * <p>
2073      * Matchers can be used to perform advanced replace behavior.
2074      * For example you could write a matcher to replace
2075      * where the character 'a' is followed by a number.
2076      *
2077      * @param matcher  the matcher to use to find the deletion, null causes no action
2078      * @param replaceStr  the replace string, null is equivalent to an empty string
2079      * @return this, to enable chaining
2080      */
2081     public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
2082         return replace(matcher, replaceStr, 0, size, 1);
2083     }
2084 
2085     // -----------------------------------------------------------------------
2086     /**
2087      * Advanced search and replaces within the builder using a matcher.
2088      * <p>
2089      * Matchers can be used to perform advanced behavior.
2090      * For example you could write a matcher to delete all occurrences
2091      * where the character 'a' is followed by a number.
2092      *
2093      * @param matcher  the matcher to use to find the deletion, null causes no action
2094      * @param replaceStr  the string to replace the match with, null is a delete
2095      * @param startIndex  the start index, inclusive, must be valid
2096      * @param endIndex  the end index, exclusive, must be valid except
2097      *  that if too large it is treated as end of string
2098      * @param replaceCount  the number of times to replace, -1 for replace all
2099      * @return this, to enable chaining
2100      * @throws IndexOutOfBoundsException if start index is invalid
2101      */
2102     public StrBuilder replace(
2103             final StrMatcher matcher, final String replaceStr,
2104             final int startIndex, int endIndex, final int replaceCount) {
2105         endIndex = validateRange(startIndex, endIndex);
2106         return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2107     }
2108 
2109     /**
2110      * Replaces within the builder using a matcher.
2111      * <p>
2112      * Matchers can be used to perform advanced behavior.
2113      * For example you could write a matcher to delete all occurrences
2114      * where the character 'a' is followed by a number.
2115      *
2116      * @param matcher  the matcher to use to find the deletion, null causes no action
2117      * @param replaceStr  the string to replace the match with, null is a delete
2118      * @param from  the start index, must be valid
2119      * @param to  the end index (exclusive), must be valid
2120      * @param replaceCount  the number of times to replace, -1 for replace all
2121      * @return this, to enable chaining
2122      * @throws IndexOutOfBoundsException if any index is invalid
2123      */
2124     private StrBuilder replaceImpl(
2125             final StrMatcher matcher, final String replaceStr,
2126             final int from, int to, int replaceCount) {
2127         if (matcher == null || size == 0) {
2128             return this;
2129         }
2130         final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
2131         for (int i = from; i < to && replaceCount != 0; i++) {
2132             final char[] buf = buffer;
2133             final int removeLen = matcher.isMatch(buf, i, from, to);
2134             if (removeLen > 0) {
2135                 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2136                 to = to - removeLen + replaceLen;
2137                 i = i + replaceLen - 1;
2138                 if (replaceCount > 0) {
2139                     replaceCount--;
2140                 }
2141             }
2142         }
2143         return this;
2144     }
2145 
2146     //-----------------------------------------------------------------------
2147     /**
2148      * Reverses the string builder placing each character in the opposite index.
2149      *
2150      * @return this, to enable chaining
2151      */
2152     public StrBuilder reverse() {
2153         if (size == 0) {
2154             return this;
2155         }
2156 
2157         final int half = size / 2;
2158         final char[] buf = buffer;
2159         for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2160             final char swap = buf[leftIdx];
2161             buf[leftIdx] = buf[rightIdx];
2162             buf[rightIdx] = swap;
2163         }
2164         return this;
2165     }
2166 
2167     //-----------------------------------------------------------------------
2168     /**
2169      * Trims the builder by removing characters less than or equal to a space
2170      * from the beginning and end.
2171      *
2172      * @return this, to enable chaining
2173      */
2174     public StrBuilder trim() {
2175         if (size == 0) {
2176             return this;
2177         }
2178         int len = size;
2179         final char[] buf = buffer;
2180         int pos = 0;
2181         while (pos < len && buf[pos] <= ' ') {
2182             pos++;
2183         }
2184         while (pos < len && buf[len - 1] <= ' ') {
2185             len--;
2186         }
2187         if (len < size) {
2188             delete(len, size);
2189         }
2190         if (pos > 0) {
2191             delete(0, pos);
2192         }
2193         return this;
2194     }
2195 
2196     //-----------------------------------------------------------------------
2197     /**
2198      * Checks whether this builder starts with the specified string.
2199      * <p>
2200      * Note that this method handles null input quietly, unlike String.
2201      *
2202      * @param str  the string to search for, null returns false
2203      * @return true if the builder starts with the string
2204      */
2205     public boolean startsWith(final String str) {
2206         if (str == null) {
2207             return false;
2208         }
2209         final int len = str.length();
2210         if (len == 0) {
2211             return true;
2212         }
2213         if (len > size) {
2214             return false;
2215         }
2216         for (int i = 0; i < len; i++) {
2217             if (buffer[i] != str.charAt(i)) {
2218                 return false;
2219             }
2220         }
2221         return true;
2222     }
2223 
2224     /**
2225      * Checks whether this builder ends with the specified string.
2226      * <p>
2227      * Note that this method handles null input quietly, unlike String.
2228      *
2229      * @param str  the string to search for, null returns false
2230      * @return true if the builder ends with the string
2231      */
2232     public boolean endsWith(final String str) {
2233         if (str == null) {
2234             return false;
2235         }
2236         final int len = str.length();
2237         if (len == 0) {
2238             return true;
2239         }
2240         if (len > size) {
2241             return false;
2242         }
2243         int pos = size - len;
2244         for (int i = 0; i < len; i++, pos++) {
2245             if (buffer[pos] != str.charAt(i)) {
2246                 return false;
2247             }
2248         }
2249         return true;
2250     }
2251 
2252     //-----------------------------------------------------------------------
2253     /**
2254      * {@inheritDoc}
2255      * @since 3.0
2256      */
2257     @Override
2258     public CharSequence subSequence(final int startIndex, final int endIndex) {
2259       if (startIndex < 0) {
2260           throw new StringIndexOutOfBoundsException(startIndex);
2261       }
2262       if (endIndex > size) {
2263           throw new StringIndexOutOfBoundsException(endIndex);
2264       }
2265       if (startIndex > endIndex) {
2266           throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2267       }
2268       return substring(startIndex, endIndex);
2269     }
2270 
2271     /**
2272      * Extracts a portion of this string builder as a string.
2273      *
2274      * @param start  the start index, inclusive, must be valid
2275      * @return the new string
2276      * @throws IndexOutOfBoundsException if the index is invalid
2277      */
2278     public String substring(final int start) {
2279         return substring(start, size);
2280     }
2281 
2282     /**
2283      * Extracts a portion of this string builder as a string.
2284      * <p>
2285      * Note: This method treats an endIndex greater than the length of the
2286      * builder as equal to the length of the builder, and continues
2287      * without error, unlike StringBuffer or String.
2288      *
2289      * @param startIndex  the start index, inclusive, must be valid
2290      * @param endIndex  the end index, exclusive, must be valid except
2291      *  that if too large it is treated as end of string
2292      * @return the new string
2293      * @throws IndexOutOfBoundsException if the index is invalid
2294      */
2295     public String substring(final int startIndex, int endIndex) {
2296         endIndex = validateRange(startIndex, endIndex);
2297         return new String(buffer, startIndex, endIndex - startIndex);
2298     }
2299 
2300     /**
2301      * Extracts the leftmost characters from the string builder without
2302      * throwing an exception.
2303      * <p>
2304      * This method extracts the left {@code length} characters from
2305      * the builder. If this many characters are not available, the whole
2306      * builder is returned. Thus the returned string may be shorter than the
2307      * length requested.
2308      *
2309      * @param length  the number of characters to extract, negative returns empty string
2310      * @return the new string
2311      */
2312     public String leftString(final int length) {
2313         if (length <= 0) {
2314             return StringUtils.EMPTY;
2315         } else if (length >= size) {
2316             return new String(buffer, 0, size);
2317         } else {
2318             return new String(buffer, 0, length);
2319         }
2320     }
2321 
2322     /**
2323      * Extracts the rightmost characters from the string builder without
2324      * throwing an exception.
2325      * <p>
2326      * This method extracts the right {@code length} characters from
2327      * the builder. If this many characters are not available, the whole
2328      * builder is returned. Thus the returned string may be shorter than the
2329      * length requested.
2330      *
2331      * @param length  the number of characters to extract, negative returns empty string
2332      * @return the new string
2333      */
2334     public String rightString(final int length) {
2335         if (length <= 0) {
2336             return StringUtils.EMPTY;
2337         } else if (length >= size) {
2338             return new String(buffer, 0, size);
2339         } else {
2340             return new String(buffer, size - length, length);
2341         }
2342     }
2343 
2344     /**
2345      * Extracts some characters from the middle of the string builder without
2346      * throwing an exception.
2347      * <p>
2348      * This method extracts {@code length} characters from the builder
2349      * at the specified index.
2350      * If the index is negative it is treated as zero.
2351      * If the index is greater than the builder size, it is treated as the builder size.
2352      * If the length is negative, the empty string is returned.
2353      * If insufficient characters are available in the builder, as much as possible is returned.
2354      * Thus the returned string may be shorter than the length requested.
2355      *
2356      * @param index  the index to start at, negative means zero
2357      * @param length  the number of characters to extract, negative returns empty string
2358      * @return the new string
2359      */
2360     public String midString(int index, final int length) {
2361         if (index < 0) {
2362             index = 0;
2363         }
2364         if (length <= 0 || index >= size) {
2365             return StringUtils.EMPTY;
2366         }
2367         if (size <= index + length) {
2368             return new String(buffer, index, size - index);
2369         }
2370         return new String(buffer, index, length);
2371     }
2372 
2373     //-----------------------------------------------------------------------
2374     /**
2375      * Checks if the string builder contains the specified char.
2376      *
2377      * @param ch  the character to find
2378      * @return true if the builder contains the character
2379      */
2380     public boolean contains(final char ch) {
2381         final char[] thisBuf = buffer;
2382         for (int i = 0; i < this.size; i++) {
2383             if (thisBuf[i] == ch) {
2384                 return true;
2385             }
2386         }
2387         return false;
2388     }
2389 
2390     /**
2391      * Checks if the string builder contains the specified string.
2392      *
2393      * @param str  the string to find
2394      * @return true if the builder contains the string
2395      */
2396     public boolean contains(final String str) {
2397         return indexOf(str, 0) >= 0;
2398     }
2399 
2400     /**
2401      * Checks if the string builder contains a string matched using the
2402      * specified matcher.
2403      * <p>
2404      * Matchers can be used to perform advanced searching behavior.
2405      * For example you could write a matcher to search for the character
2406      * 'a' followed by a number.
2407      *
2408      * @param matcher  the matcher to use, null returns -1
2409      * @return true if the matcher finds a match in the builder
2410      */
2411     public boolean contains(final StrMatcher matcher) {
2412         return indexOf(matcher, 0) >= 0;
2413     }
2414 
2415     //-----------------------------------------------------------------------
2416     /**
2417      * Searches the string builder to find the first reference to the specified char.
2418      *
2419      * @param ch  the character to find
2420      * @return the first index of the character, or -1 if not found
2421      */
2422     public int indexOf(final char ch) {
2423         return indexOf(ch, 0);
2424     }
2425 
2426     /**
2427      * Searches the string builder to find the first reference to the specified char.
2428      *
2429      * @param ch  the character to find
2430      * @param startIndex  the index to start at, invalid index rounded to edge
2431      * @return the first index of the character, or -1 if not found
2432      */
2433     public int indexOf(final char ch, int startIndex) {
2434         startIndex = (Math.max(startIndex, 0));
2435         if (startIndex >= size) {
2436             return -1;
2437         }
2438         final char[] thisBuf = buffer;
2439         for (int i = startIndex; i < size; i++) {
2440             if (thisBuf[i] == ch) {
2441                 return i;
2442             }
2443         }
2444         return -1;
2445     }
2446 
2447     /**
2448      * Searches the string builder to find the first reference to the specified string.
2449      * <p>
2450      * Note that a null input string will return -1, whereas the JDK throws an exception.
2451      *
2452      * @param str  the string to find, null returns -1
2453      * @return the first index of the string, or -1 if not found
2454      */
2455     public int indexOf(final String str) {
2456         return indexOf(str, 0);
2457     }
2458 
2459     /**
2460      * Searches the string builder to find the first reference to the specified
2461      * string starting searching from the given index.
2462      * <p>
2463      * Note that a null input string will return -1, whereas the JDK throws an exception.
2464      *
2465      * @param str  the string to find, null returns -1
2466      * @param startIndex  the index to start at, invalid index rounded to edge
2467      * @return the first index of the string, or -1 if not found
2468      */
2469     public int indexOf(final String str, int startIndex) {
2470         startIndex = (Math.max(startIndex, 0));
2471         if (str == null || startIndex >= size) {
2472             return -1;
2473         }
2474         final int strLen = str.length();
2475         if (strLen == 1) {
2476             return indexOf(str.charAt(0), startIndex);
2477         }
2478         if (strLen == 0) {
2479             return startIndex;
2480         }
2481         if (strLen > size) {
2482             return -1;
2483         }
2484         final char[] thisBuf = buffer;
2485         final int len = size - strLen + 1;
2486         outer:
2487         for (int i = startIndex; i < len; i++) {
2488             for (int j = 0; j < strLen; j++) {
2489                 if (str.charAt(j) != thisBuf[i + j]) {
2490                     continue outer;
2491                 }
2492             }
2493             return i;
2494         }
2495         return -1;
2496     }
2497 
2498     /**
2499      * Searches the string builder using the matcher to find the first match.
2500      * <p>
2501      * Matchers can be used to perform advanced searching behavior.
2502      * For example you could write a matcher to find the character 'a'
2503      * followed by a number.
2504      *
2505      * @param matcher  the matcher to use, null returns -1
2506      * @return the first index matched, or -1 if not found
2507      */
2508     public int indexOf(final StrMatcher matcher) {
2509         return indexOf(matcher, 0);
2510     }
2511 
2512     /**
2513      * Searches the string builder using the matcher to find the first
2514      * match searching from the given index.
2515      * <p>
2516      * Matchers can be used to perform advanced searching behavior.
2517      * For example you could write a matcher to find the character 'a'
2518      * followed by a number.
2519      *
2520      * @param matcher  the matcher to use, null returns -1
2521      * @param startIndex  the index to start at, invalid index rounded to edge
2522      * @return the first index matched, or -1 if not found
2523      */
2524     public int indexOf(final StrMatcher matcher, int startIndex) {
2525         startIndex = (Math.max(startIndex, 0));
2526         if (matcher == null || startIndex >= size) {
2527             return -1;
2528         }
2529         final int len = size;
2530         final char[] buf = buffer;
2531         for (int i = startIndex; i < len; i++) {
2532             if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2533                 return i;
2534             }
2535         }
2536         return -1;
2537     }
2538 
2539     //-----------------------------------------------------------------------
2540     /**
2541      * Searches the string builder to find the last reference to the specified char.
2542      *
2543      * @param ch  the character to find
2544      * @return the last index of the character, or -1 if not found
2545      */
2546     public int lastIndexOf(final char ch) {
2547         return lastIndexOf(ch, size - 1);
2548     }
2549 
2550     /**
2551      * Searches the string builder to find the last reference to the specified char.
2552      *
2553      * @param ch  the character to find
2554      * @param startIndex  the index to start at, invalid index rounded to edge
2555      * @return the last index of the character, or -1 if not found
2556      */
2557     public int lastIndexOf(final char ch, int startIndex) {
2558         startIndex = (startIndex >= size ? size - 1 : startIndex);
2559         if (startIndex < 0) {
2560             return -1;
2561         }
2562         for (int i = startIndex; i >= 0; i--) {
2563             if (buffer[i] == ch) {
2564                 return i;
2565             }
2566         }
2567         return -1;
2568     }
2569 
2570     /**
2571      * Searches the string builder to find the last reference to the specified string.
2572      * <p>
2573      * Note that a null input string will return -1, whereas the JDK throws an exception.
2574      *
2575      * @param str  the string to find, null returns -1
2576      * @return the last index of the string, or -1 if not found
2577      */
2578     public int lastIndexOf(final String str) {
2579         return lastIndexOf(str, size - 1);
2580     }
2581 
2582     /**
2583      * Searches the string builder to find the last reference to the specified
2584      * string starting searching from the given index.
2585      * <p>
2586      * Note that a null input string will return -1, whereas the JDK throws an exception.
2587      *
2588      * @param str  the string to find, null returns -1
2589      * @param startIndex  the index to start at, invalid index rounded to edge
2590      * @return the last index of the string, or -1 if not found
2591      */
2592     public int lastIndexOf(final String str, int startIndex) {
2593         startIndex = (startIndex >= size ? size - 1 : startIndex);
2594         if (str == null || startIndex < 0) {
2595             return -1;
2596         }
2597         final int strLen = str.length();
2598         if (strLen > 0 && strLen <= size) {
2599             if (strLen == 1) {
2600                 return lastIndexOf(str.charAt(0), startIndex);
2601             }
2602 
2603             outer:
2604             for (int i = startIndex - strLen + 1; i >= 0; i--) {
2605                 for (int j = 0; j < strLen; j++) {
2606                     if (str.charAt(j) != buffer[i + j]) {
2607                         continue outer;
2608                     }
2609                 }
2610                 return i;
2611             }
2612 
2613         } else if (strLen == 0) {
2614             return startIndex;
2615         }
2616         return -1;
2617     }
2618 
2619     /**
2620      * Searches the string builder using the matcher to find the last match.
2621      * <p>
2622      * Matchers can be used to perform advanced searching behavior.
2623      * For example you could write a matcher to find the character 'a'
2624      * followed by a number.
2625      *
2626      * @param matcher  the matcher to use, null returns -1
2627      * @return the last index matched, or -1 if not found
2628      */
2629     public int lastIndexOf(final StrMatcher matcher) {
2630         return lastIndexOf(matcher, size);
2631     }
2632 
2633     /**
2634      * Searches the string builder using the matcher to find the last
2635      * match searching from the given index.
2636      * <p>
2637      * Matchers can be used to perform advanced searching behavior.
2638      * For example you could write a matcher to find the character 'a'
2639      * followed by a number.
2640      *
2641      * @param matcher  the matcher to use, null returns -1
2642      * @param startIndex  the index to start at, invalid index rounded to edge
2643      * @return the last index matched, or -1 if not found
2644      */
2645     public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2646         startIndex = (startIndex >= size ? size - 1 : startIndex);
2647         if (matcher == null || startIndex < 0) {
2648             return -1;
2649         }
2650         final char[] buf = buffer;
2651         final int endIndex = startIndex + 1;
2652         for (int i = startIndex; i >= 0; i--) {
2653             if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2654                 return i;
2655             }
2656         }
2657         return -1;
2658     }
2659 
2660     //-----------------------------------------------------------------------
2661     /**
2662      * Creates a tokenizer that can tokenize the contents of this builder.
2663      * <p>
2664      * This method allows the contents of this builder to be tokenized.
2665      * The tokenizer will be setup by default to tokenize on space, tab,
2666      * newline and formfeed (as per StringTokenizer). These values can be
2667      * changed on the tokenizer class, before retrieving the tokens.
2668      * <p>
2669      * The returned tokenizer is linked to this builder. You may intermix
2670      * calls to the builder and tokenizer within certain limits, however
2671      * there is no synchronization. Once the tokenizer has been used once,
2672      * it must be {@link StrTokenizer#reset() reset} to pickup the latest
2673      * changes in the builder. For example:
2674      * <pre>
2675      * StrBuilder b = new StrBuilder();
2676      * b.append("a b ");
2677      * StrTokenizer t = b.asTokenizer();
2678      * String[] tokens1 = t.getTokenArray();  // returns a,b
2679      * b.append("c d ");
2680      * String[] tokens2 = t.getTokenArray();  // returns a,b (c and d ignored)
2681      * t.reset();              // reset causes builder changes to be picked up
2682      * String[] tokens3 = t.getTokenArray();  // returns a,b,c,d
2683      * </pre>
2684      * In addition to simply intermixing appends and tokenization, you can also
2685      * call the set methods on the tokenizer to alter how it tokenizes. Just
2686      * remember to call reset when you want to pickup builder changes.
2687      * <p>
2688      * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
2689      * with a non-null value will break the link with the builder.
2690      *
2691      * @return a tokenizer that is linked to this builder
2692      */
2693     public StrTokenizer asTokenizer() {
2694         return new StrBuilderTokenizer();
2695     }
2696 
2697     //-----------------------------------------------------------------------
2698     /**
2699      * Gets the contents of this builder as a Reader.
2700      * <p>
2701      * This method allows the contents of the builder to be read
2702      * using any standard method that expects a Reader.
2703      * <p>
2704      * To use, simply create a {@code StrBuilder}, populate it with
2705      * data, call {@code asReader}, and then read away.
2706      * <p>
2707      * The internal character array is shared between the builder and the reader.
2708      * This allows you to append to the builder after creating the reader,
2709      * and the changes will be picked up.
2710      * Note however, that no synchronization occurs, so you must perform
2711      * all operations with the builder and the reader in one thread.
2712      * <p>
2713      * The returned reader supports marking, and ignores the flush method.
2714      *
2715      * @return a reader that reads from this builder
2716      */
2717     public Reader asReader() {
2718         return new StrBuilderReader();
2719     }
2720 
2721     //-----------------------------------------------------------------------
2722     /**
2723      * Gets this builder as a Writer that can be written to.
2724      * <p>
2725      * This method allows you to populate the contents of the builder
2726      * using any standard method that takes a Writer.
2727      * <p>
2728      * To use, simply create a {@code StrBuilder},
2729      * call {@code asWriter}, and populate away. The data is available
2730      * at any time using the methods of the {@code StrBuilder}.
2731      * <p>
2732      * The internal character array is shared between the builder and the writer.
2733      * This allows you to intermix calls that append to the builder and
2734      * write using the writer and the changes will be occur correctly.
2735      * Note however, that no synchronization occurs, so you must perform
2736      * all operations with the builder and the writer in one thread.
2737      * <p>
2738      * The returned writer ignores the close and flush methods.
2739      *
2740      * @return a writer that populates this builder
2741      */
2742     public Writer asWriter() {
2743         return new StrBuilderWriter();
2744     }
2745 
2746     /**
2747      * Appends current contents of this {@code StrBuilder} to the
2748      * provided {@link Appendable}.
2749      * <p>
2750      * This method tries to avoid doing any extra copies of contents.
2751      *
2752      * @param appendable  the appendable to append data to
2753      * @throws IOException  if an I/O error occurs
2754      *
2755      * @since 3.4
2756      * @see #readFrom(Readable)
2757      */
2758     public void appendTo(final Appendable appendable) throws IOException {
2759         if (appendable instanceof Writer) {
2760             ((Writer) appendable).write(buffer, 0, size);
2761         } else if (appendable instanceof StringBuilder) {
2762             ((StringBuilder) appendable).append(buffer, 0, size);
2763         } else if (appendable instanceof StringBuffer) {
2764             ((StringBuffer) appendable).append(buffer, 0, size);
2765         } else if (appendable instanceof CharBuffer) {
2766             ((CharBuffer) appendable).put(buffer, 0, size);
2767         } else {
2768             appendable.append(this);
2769         }
2770     }
2771 
2772     /**
2773      * Checks the contents of this builder against another to see if they
2774      * contain the same character content ignoring case.
2775      *
2776      * @param other  the object to check, null returns false
2777      * @return true if the builders contain the same characters in the same order
2778      */
2779     public boolean equalsIgnoreCase(final StrBuilder other) {
2780         if (this == other) {
2781             return true;
2782         }
2783         if (this.size != other.size) {
2784             return false;
2785         }
2786         final char[] thisBuf = this.buffer;
2787         final char[] otherBuf = other.buffer;
2788         for (int i = size - 1; i >= 0; i--) {
2789             final char c1 = thisBuf[i];
2790             final char c2 = otherBuf[i];
2791             if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
2792                 return false;
2793             }
2794         }
2795         return true;
2796     }
2797 
2798     /**
2799      * Checks the contents of this builder against another to see if they
2800      * contain the same character content.
2801      *
2802      * @param other  the object to check, null returns false
2803      * @return true if the builders contain the same characters in the same order
2804      */
2805     public boolean equals(final StrBuilder other) {
2806         if (this == other) {
2807             return true;
2808         }
2809         if (other == null) {
2810             return false;
2811         }
2812         if (this.size != other.size) {
2813             return false;
2814         }
2815         final char[] thisBuf = this.buffer;
2816         final char[] otherBuf = other.buffer;
2817         for (int i = size - 1; i >= 0; i--) {
2818             if (thisBuf[i] != otherBuf[i]) {
2819                 return false;
2820             }
2821         }
2822         return true;
2823     }
2824 
2825     /**
2826      * Checks the contents of this builder against another to see if they
2827      * contain the same character content.
2828      *
2829      * @param obj  the object to check, null returns false
2830      * @return true if the builders contain the same characters in the same order
2831      */
2832     @Override
2833     public boolean equals(final Object obj) {
2834         return obj instanceof StrBuilder./org/apache/commons/lang3/text/StrBuilder.html#StrBuilder">StrBuilder && equals((StrBuilder) obj);
2835     }
2836 
2837     /**
2838      * Gets a suitable hash code for this builder.
2839      *
2840      * @return a hash code
2841      */
2842     @Override
2843     public int hashCode() {
2844         final char[] buf = buffer;
2845         int hash = 0;
2846         for (int i = size - 1; i >= 0; i--) {
2847             hash = 31 * hash + buf[i];
2848         }
2849         return hash;
2850     }
2851 
2852     //-----------------------------------------------------------------------
2853     /**
2854      * Gets a String version of the string builder, creating a new instance
2855      * each time the method is called.
2856      * <p>
2857      * Note that unlike StringBuffer, the string version returned is
2858      * independent of the string builder.
2859      *
2860      * @return the builder as a String
2861      */
2862     @Override
2863     public String toString() {
2864         return new String(buffer, 0, size);
2865     }
2866 
2867     /**
2868      * Gets a StringBuffer version of the string builder, creating a
2869      * new instance each time the method is called.
2870      *
2871      * @return the builder as a StringBuffer
2872      */
2873     public StringBuffer toStringBuffer() {
2874         return new StringBuffer(size).append(buffer, 0, size);
2875     }
2876 
2877     /**
2878      * Gets a StringBuilder version of the string builder, creating a
2879      * new instance each time the method is called.
2880      *
2881      * @return the builder as a StringBuilder
2882      * @since 3.2
2883      */
2884     public StringBuilder toStringBuilder() {
2885         return new StringBuilder(size).append(buffer, 0, size);
2886     }
2887 
2888     /**
2889      * Implement the {@link Builder} interface.
2890      * @return the builder as a String
2891      * @since 3.2
2892      * @see #toString()
2893      */
2894     @Override
2895     public String build() {
2896         return toString();
2897     }
2898 
2899     //-----------------------------------------------------------------------
2900     /**
2901      * Validates parameters defining a range of the builder.
2902      *
2903      * @param startIndex  the start index, inclusive, must be valid
2904      * @param endIndex  the end index, exclusive, must be valid except
2905      *  that if too large it is treated as end of string
2906      * @return the new string
2907      * @throws IndexOutOfBoundsException if the index is invalid
2908      */
2909     protected int validateRange(final int startIndex, int endIndex) {
2910         if (startIndex < 0) {
2911             throw new StringIndexOutOfBoundsException(startIndex);
2912         }
2913         if (endIndex > size) {
2914             endIndex = size;
2915         }
2916         if (startIndex > endIndex) {
2917             throw new StringIndexOutOfBoundsException("end < start");
2918         }
2919         return endIndex;
2920     }
2921 
2922     /**
2923      * Validates parameters defining a single index in the builder.
2924      *
2925      * @param index  the index, must be valid
2926      * @throws IndexOutOfBoundsException if the index is invalid
2927      */
2928     protected void validateIndex(final int index) {
2929         if (index < 0 || index > size) {
2930             throw new StringIndexOutOfBoundsException(index);
2931         }
2932     }
2933 
2934     //-----------------------------------------------------------------------
2935     /**
2936      * Inner class to allow StrBuilder to operate as a tokenizer.
2937      */
2938     class StrBuilderTokenizer extends StrTokenizer {
2939 
2940         /**
2941          * Default constructor.
2942          */
2943         StrBuilderTokenizer() {
2944         }
2945 
2946         /** {@inheritDoc} */
2947         @Override
2948         protected List<String> tokenize(final char[] chars, final int offset, final int count) {
2949             if (chars == null) {
2950                 return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
2951             }
2952             return super.tokenize(chars, offset, count);
2953         }
2954 
2955         /** {@inheritDoc} */
2956         @Override
2957         public String getContent() {
2958             final String str = super.getContent();
2959             if (str == null) {
2960                 return StrBuilder.this.toString();
2961             }
2962             return str;
2963         }
2964     }
2965 
2966     //-----------------------------------------------------------------------
2967     /**
2968      * Inner class to allow StrBuilder to operate as a reader.
2969      */
2970     class StrBuilderReader extends Reader {
2971         /** The current stream position. */
2972         private int pos;
2973         /** The last mark position. */
2974         private int mark;
2975 
2976         /**
2977          * Default constructor.
2978          */
2979         StrBuilderReader() {
2980         }
2981 
2982         /** {@inheritDoc} */
2983         @Override
2984         public void close() {
2985             // do nothing
2986         }
2987 
2988         /** {@inheritDoc} */
2989         @Override
2990         public int read() {
2991             if (ready() == false) {
2992                 return -1;
2993             }
2994             return StrBuilder.this.charAt(pos++);
2995         }
2996 
2997         /** {@inheritDoc} */
2998         @Override
2999         public int read(final char[] b, final int off, int len) {
3000             if (off < 0 || len < 0 || off > b.length ||
3001                     (off + len) > b.length || (off + len) < 0) {
3002                 throw new IndexOutOfBoundsException();
3003             }
3004             if (len == 0) {
3005                 return 0;
3006             }
3007             if (pos >= StrBuilder.this.size()) {
3008                 return -1;
3009             }
3010             if (pos + len > size()) {
3011                 len = StrBuilder.this.size() - pos;
3012             }
3013             StrBuilder.this.getChars(pos, pos + len, b, off);
3014             pos += len;
3015             return len;
3016         }
3017 
3018         /** {@inheritDoc} */
3019         @Override
3020         public long skip(long n) {
3021             if (pos + n > StrBuilder.this.size()) {
3022                 n = StrBuilder.this.size() - pos;
3023             }
3024             if (n < 0) {
3025                 return 0;
3026             }
3027             pos += n;
3028             return n;
3029         }
3030 
3031         /** {@inheritDoc} */
3032         @Override
3033         public boolean ready() {
3034             return pos < StrBuilder.this.size();
3035         }
3036 
3037         /** {@inheritDoc} */
3038         @Override
3039         public boolean markSupported() {
3040             return true;
3041         }
3042 
3043         /** {@inheritDoc} */
3044         @Override
3045         public void mark(final int readAheadLimit) {
3046             mark = pos;
3047         }
3048 
3049         /** {@inheritDoc} */
3050         @Override
3051         public void reset() {
3052             pos = mark;
3053         }
3054     }
3055 
3056     //-----------------------------------------------------------------------
3057     /**
3058      * Inner class to allow StrBuilder to operate as a writer.
3059      */
3060     class StrBuilderWriter extends Writer {
3061 
3062         /**
3063          * Default constructor.
3064          */
3065         StrBuilderWriter() {
3066         }
3067 
3068         /** {@inheritDoc} */
3069         @Override
3070         public void close() {
3071             // do nothing
3072         }
3073 
3074         /** {@inheritDoc} */
3075         @Override
3076         public void flush() {
3077             // do nothing
3078         }
3079 
3080         /** {@inheritDoc} */
3081         @Override
3082         public void write(final int c) {
3083             StrBuilder.this.append((char) c);
3084         }
3085 
3086         /** {@inheritDoc} */
3087         @Override
3088         public void write(final char[] cbuf) {
3089             StrBuilder.this.append(cbuf);
3090         }
3091 
3092         /** {@inheritDoc} */
3093         @Override
3094         public void write(final char[] cbuf, final int off, final int len) {
3095             StrBuilder.this.append(cbuf, off, len);
3096         }
3097 
3098         /** {@inheritDoc} */
3099         @Override
3100         public void write(final String str) {
3101             StrBuilder.this.append(str);
3102         }
3103 
3104         /** {@inheritDoc} */
3105         @Override
3106         public void write(final String str, final int off, final int len) {
3107             StrBuilder.this.append(str, off, len);
3108         }
3109     }
3110 
3111 }