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