    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>{@code
    1252     * for (int i = 0; i < list.size(); i++) {
    1253     *   appendSeparator(",", i);
    1254     *   append(list.get(i));
    1255     * }
    1256     * }
    1257     * </pre>
    1258     * Note that for this simple example, you should use
    1259     * {@link #appendWithSeparators(Iterable, String)}.
    1260     *
    1261     * @param separator  the separator to use
    1262     * @param loopIndex  the loop index
    1263     * @return this, to enable chaining
    1264     * @since 2.3
    1265     */
    1266    public StrBuilder appendSeparator(final char separator, final int loopIndex) {
    1267        if (loopIndex > 0) {
    1268            append(separator);
    1269        }
    1270        return this;
    1271    }
    1272
    1273    /**
    1274     * Appends a separator if the builder is currently non-empty.
    1275     * Appending a null separator will have no effect.
    1276     * The separator is appended using {@link #append(String)}.
    1277     * <p>
    1278     * This method is useful for adding a separator each time around the
    1279     * loop except the first.
    1280     * </p>
    1281     * <pre>
    1282     * for (Iterator it = list.iterator(); it.hasNext(); ) {
    1283     *   appendSeparator(",");
    1284     *   append(it.next());
    1285     * }
    1286     * </pre>
    1287     * <p>
    1288     * Note that for this simple example, you should use
    1289     * {@link #appendWithSeparators(Iterable, String)}.
    1290     * </p>
    1291     *
    1292     * @param separator  the separator to use, null means no separator
    1293     * @return this, to enable chaining
    1294     * @since 2.3
    1295     */
    1296    public StrBuilder appendSeparator(final String separator) {
    1297        return appendSeparator(separator, null);
    1298    }
    1299
    1300    /**
    1301     * Appends a separator to the builder if the loop index is greater than zero.
    1302     * Appending a null separator will have no effect.
    1303     * The separator is appended using {@link #append(String)}.
    1304     * <p>
    1305     * This method is useful for adding a separator each time around the
    1306     * loop except the first.
    1307     * </p>
    1308     * <pre>{@code
    1309     * for (int i = 0; i < list.size(); i++) {
    1310     *   appendSeparator(",", i);
    1311     *   append(list.get(i));
    1312     * }
    1313     * }</pre>
    1314     * Note that for this simple example, you should use
    1315     * {@link #appendWithSeparators(Iterable, String)}.
    1316     *
    1317     * @param separator  the separator to use, null means no separator
    1318     * @param loopIndex  the loop index
    1319     * @return this, to enable chaining
    1320     * @since 2.3
    1321     */
    1322    public StrBuilder appendSeparator(final String separator, final int loopIndex) {
    1323        if (separator != null && loopIndex > 0) {
    1324            append(separator);
    1325        }
    1326        return this;
    1327    }
    1328
    1329    /**
    1330     * Appends one of both separators to the StrBuilder.
    1331     * If the builder is currently empty it will append the defaultIfEmpty-separator
    1332     * Otherwise it will append the standard-separator
    1333     *
    1334     * Appending a null separator will have no effect.
    1335     * The separator is appended using {@link #append(String)}.
    1336     * <p>
    1337     * This method is for example useful for constructing queries
    1338     * </p>
    1339     * <pre>
    1340     * StrBuilder whereClause = new StrBuilder();
    1341     * if (searchCommand.getPriority() != null) {
    1342     *  whereClause.appendSeparator(" and", " where");
    1343     *  whereClause.append(" priority = ?")
    1344     * }
    1345     * if (searchCommand.getComponent() != null) {
    1346     *  whereClause.appendSeparator(" and", " where");
    1347     *  whereClause.append(" component = ?")
    1348     * }
    1349     * selectClause.append(whereClause)
    1350     * </pre>
    1351     *
    1352     * @param standard the separator if builder is not empty, null means no separator
    1353     * @param defaultIfEmpty the separator if builder is empty, null means no separator
    1354     * @return this, to enable chaining
    1355     * @since 2.5
    1356     */
    1357    public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
    1358        final String str = isEmpty() ? defaultIfEmpty : standard;
    1359        if (str != null) {
    1360            append(str);
    1361        }
    1362        return this;
    1363    }
    1364
    1365    /**
    1366     * Appends current contents of this {@link StrBuilder} to the
    1367     * provided {@link Appendable}.
    1368     * <p>
    1369     * This method tries to avoid doing any extra copies of contents.
    1370     * </p>
    1371     *
    1372     * @param appendable  the appendable to append data to
    1373     * @throws IOException  if an I/O error occurs
    1374     *
    1375     * @since 3.4
    1376     * @see #readFrom(Readable)
    1377     */
    1378    public void appendTo(final Appendable appendable) throws IOException {
    1379        if (appendable instanceof Writer) {
    1380            ((Writer) appendable).write(buffer, 0, size);
    1381        } else if (appendable instanceof StringBuilder) {
    1382            ((StringBuilder) appendable).append(buffer, 0, size);
    1383        } else if (appendable instanceof StringBuffer) {
    1384            ((StringBuffer) appendable).append(buffer, 0, size);
    1385        } else if (appendable instanceof CharBuffer) {
    1386            ((CharBuffer) appendable).put(buffer, 0, size);
    1387        } else {
    1388            appendable.append(this);
    1389        }
    1390    }
    1391
    1392    /**
    1393     * Appends an iterable placing separators between each value, but
    1394     * not before the first or after the last.
    1395     * Appending a null iterable will have no effect.
    1396     * Each object is appended using {@link #append(Object)}.
    1397     *
    1398     * @param iterable  the iterable to append
    1399     * @param separator  the separator to use, null means no separator
    1400     * @return this, to enable chaining
    1401     */
    1402    public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
    1403        if (iterable != null) {
    1404            final String sep = Objects.toString(separator, "");
    1405            final Iterator<?> it = iterable.iterator();
    1406            while (it.hasNext()) {
    1407                append(it.next());
    1408                if (it.hasNext()) {
    1409                    append(sep);
    1410                }
    1411            }
    1412        }
    1413        return this;
    1414    }
    1415
    1416    /**
    1417     * Appends an iterator placing separators between each value, but
    1418     * not before the first or after the last.
    1419     * Appending a null iterator will have no effect.
    1420     * Each object is appended using {@link #append(Object)}.
    1421     *
    1422     * @param it  the iterator to append
    1423     * @param separator  the separator to use, null means no separator
    1424     * @return this, to enable chaining
    1425     */
    1426    public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
    1427        if (it != null) {
    1428            final String sep = Objects.toString(separator, "");
    1429            while (it.hasNext()) {
    1430                append(it.next());
    1431                if (it.hasNext()) {
    1432                    append(sep);
    1433                }
    1434            }
    1435        }
    1436        return this;
    1437    }
    1438
    1439    /**
    1440     * Appends an array placing separators between each value, but
    1441     * not before the first or after the last.
    1442     * Appending a null array will have no effect.
    1443     * Each object is appended using {@link #append(Object)}.
    1444     *
    1445     * @param array  the array to append
    1446     * @param separator  the separator to use, null means no separator
    1447     * @return this, to enable chaining
    1448     */
    1449    public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
    1450        if (array != null && array.length > 0) {
    1451            final String sep = Objects.toString(separator, "");
    1452            append(array[0]);
    1453            for (int i = 1; i < array.length; i++) {
    1454                append(sep);
    1455                append(array[i]);
    1456            }
    1457        }
    1458        return this;
    1459    }
    1460
    1461    /**
    1462     * Gets the contents of this builder as a Reader.
    1463     * <p>
    1464     * This method allows the contents of the builder to be read
    1465     * using any standard method that expects a Reader.
    1466     * </p>
    1467     * <p>
    1468     * To use, simply create a {@link StrBuilder}, populate it with
    1469     * data, call {@code asReader}, and then read away.
    1470     * </p>
    1471     * <p>
    1472     * The internal character array is shared between the builder and the reader.
    1473     * This allows you to append to the builder after creating the reader,
    1474     * and the changes will be picked up.
    1475     * Note however, that no synchronization occurs, so you must perform
    1476     * all operations with the builder and the reader in one thread.
    1477     * </p>
    1478     * <p>
    1479     * The returned reader supports marking, and ignores the flush method.
    1480     * </p>
    1481     *
    1482     * @return a reader that reads from this builder
    1483     */
    1484    public Reader asReader() {
    1485        return new StrBuilderReader();
    1486    }
    1487
    1488    /**
    1489     * Creates a tokenizer that can tokenize the contents of this builder.
    1490     * <p>
    1491     * This method allows the contents of this builder to be tokenized.
    1492     * The tokenizer will be setup by default to tokenize on space, tab,
    1493     * newline and formfeed (as per StringTokenizer). These values can be
    1494     * changed on the tokenizer class, before retrieving the tokens.
    1495     * </p>
    1496     * <p>
    1497     * The returned tokenizer is linked to this builder. You may intermix
    1498     * calls to the builder and tokenizer within certain limits, however
    1499     * there is no synchronization. Once the tokenizer has been used once,
    1500     * it must be {@link StrTokenizer#reset() reset} to pickup the latest
    1501     * changes in the builder. For example:
    1502     * </p>
    1503     * <pre>
    1504     * StrBuilder b = new StrBuilder();
    1505     * b.append("a b ");
    1506     * StrTokenizer t = b.asTokenizer();
    1507     * String[] tokens1 = t.getTokenArray();  // returns a,b
    1508     * b.append("c d ");
    1509     * String[] tokens2 = t.getTokenArray();  // returns a,b (c and d ignored)
    1510     * t.reset();              // reset causes builder changes to be picked up
    1511     * String[] tokens3 = t.getTokenArray();  // returns a,b,c,d
    1512     * </pre>
    1513     * <p>
    1514     * In addition to simply intermixing appends and tokenization, you can also
    1515     * call the set methods on the tokenizer to alter how it tokenizes. Just
    1516     * remember to call reset when you want to pickup builder changes.
    1517     * </p>
    1518     * <p>
    1519     * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
    1520     * with a non-null value will break the link with the builder.
    1521     * </p>
    1522     *
    1523     * @return a tokenizer that is linked to this builder
    1524     */
    1525    public StrTokenizer asTokenizer() {
    1526        return new StrBuilderTokenizer();
    1527    }
    1528
    1529    /**
    1530     * Gets this builder as a Writer that can be written to.
    1531     * <p>
    1532     * This method allows you to populate the contents of the builder
    1533     * using any standard method that takes a Writer.
    1534     * </p>
    1535     * <p>
    1536     * To use, simply create a {@link StrBuilder},
    1537     * call {@code asWriter}, and populate away. The data is available
    1538     * at any time using the methods of the {@link StrBuilder}.
    1539     * </p>
    1540     * <p>
    1541     * The internal character array is shared between the builder and the writer.
    1542     * This allows you to intermix calls that append to the builder and
    1543     * write using the writer and the changes will be occur correctly.
    1544     * Note however, that no synchronization occurs, so you must perform
    1545     * all operations with the builder and the writer in one thread.
    1546     * </p>
    1547     * <p>
    1548     * The returned writer ignores the close and flush methods.
    1549     * </p>
    1550     *
    1551     * @return a writer that populates this builder
    1552     */
    1553    public Writer asWriter() {
    1554        return new StrBuilderWriter();
    1555    }
    1556
    1557    /**
    1558     * Implement the {@link Builder} interface.
    1559     * @return the builder as a String
    1560     * @since 3.2
    1561     * @see #toString()
    1562     */
    1563    @Override
    1564    public String build() {
    1565        return toString();
    1566    }
    1567
    1568    /**
    1569     * Gets the current size of the internal character array buffer.
    1570     *
    1571     * @return the capacity
    1572     */
    1573    public int capacity() {
    1574        return buffer.length;
    1575    }
    1576
    1577    /**
    1578     * Gets the character at the specified index.
    1579     *
    1580     * @see #setCharAt(int, char)
    1581     * @see #deleteCharAt(int)
    1582     * @param index  the index to retrieve, must be valid
    1583     * @return the character at the index
    1584     * @throws IndexOutOfBoundsException if the index is invalid
    1585     */
    1586    @Override
    1587    public char charAt(final int index) {
    1588        if (index < 0 || index >= length()) {
    1589            throw new StringIndexOutOfBoundsException(index);
    1590        }
    1591        return buffer[index];
    1592    }
    1593
    1594    /**
    1595     * Clears the string builder (convenience Collections API style method).
    1596     * <p>
    1597     * This method does not reduce the size of the internal character buffer.
    1598     * To do that, call {@code clear()} followed by {@link #minimizeCapacity()}.
    1599     * </p>
    1600     * <p>
    1601     * This method is the same as {@link #setLength(int)} called with zero
    1602     * and is provided to match the API of Collections.
    1603     * </p>
    1604     *
    1605     * @return this, to enable chaining
    1606     */
    1607    public StrBuilder clear() {
    1608        size = 0;
    1609        return this;
    1610    }
    1611
    1612    /**
    1613     * Checks if the string builder contains the specified char.
    1614     *
    1615     * @param ch  the character to find
    1616     * @return true if the builder contains the character
    1617     */
    1618    public boolean contains(final char ch) {
    1619        final char[] thisBuf = buffer;
    1620        for (int i = 0; i < this.size; i++) {
    1621            if (thisBuf[i] == ch) {
    1622                return true;
    1623            }
    1624        }
    1625        return false;
    1626    }
    1627
    1628    /**
    1629     * Checks if the string builder contains the specified string.
    1630     *
    1631     * @param str  the string to find
    1632     * @return true if the builder contains the string
    1633     */
    1634    public boolean contains(final String str) {
    1635        return indexOf(str, 0) >= 0;
    1636    }
    1637
    1638    /**
    1639     * Checks if the string builder contains a string matched using the
    1640     * specified matcher.
    1641     * <p>
    1642     * Matchers can be used to perform advanced searching behavior.
    1643     * For example you could write a matcher to search for the character
    1644     * 'a' followed by a number.
    1645     * </p>
    1646     *
    1647     * @param matcher  the matcher to use, null returns -1
    1648     * @return true if the matcher finds a match in the builder
    1649     */
    1650    public boolean contains(final StrMatcher matcher) {
    1651        return indexOf(matcher, 0) >= 0;
    1652    }
    1653    /**
    1654     * Deletes the characters between the two specified indices.
    1655     *
    1656     * @param startIndex  the start index, inclusive, must be valid
    1657     * @param endIndex  the end index, exclusive, must be valid except
    1658     *  that if too large it is treated as end of string
    1659     * @return this, to enable chaining
    1660     * @throws IndexOutOfBoundsException if the index is invalid
    1661     */
    1662    public StrBuilder delete(final int startIndex, int endIndex) {
    1663        endIndex = validateRange(startIndex, endIndex);
    1664        final int len = endIndex - startIndex;
    1665        if (len > 0) {
    1666            deleteImpl(startIndex, endIndex, len);
    1667        }
    1668        return this;
    1669    }
    1670
    1671    /**
    1672     * Deletes the character wherever it occurs in the builder.
    1673     *
    1674     * @param ch  the character to delete
    1675     * @return this, to enable chaining
    1676     */
    1677    public StrBuilder deleteAll(final char ch) {
    1678        for (int i = 0; i < size; i++) {
    1679            if (buffer[i] == ch) {
    1680                final int start = i;
    1681                while (++i < size) {
    1682                    if (buffer[i] != ch) {
    1683                        break;
    1684                    }
    1685                }
    1686                final int len = i - start;
    1687                deleteImpl(start, i, len);
    1688                i -= len;
    1689            }
    1690        }
    1691        return this;
    1692    }
    1693
    1694    /**
    1695     * Deletes the string wherever it occurs in the builder.
    1696     *
    1697     * @param str  the string to delete, null causes no action
    1698     * @return this, to enable chaining
    1699     */
    1700    public StrBuilder deleteAll(final String str) {
    1701        final int len = StringUtils.length(str);
    1702        if (len > 0) {
    1703            int index = indexOf(str, 0);
    1704            while (index >= 0) {
    1705                deleteImpl(index, index + len, len);
    1706                index = indexOf(str, index);
    1707            }
    1708        }
    1709        return this;
    1710    }
    1711
    1712    /**
    1713     * Deletes all parts of the builder that the matcher matches.
    1714     * <p>
    1715     * Matchers can be used to perform advanced deletion behavior.
    1716     * For example you could write a matcher to delete all occurrences
    1717     * where the character 'a' is followed by a number.
    1718     * </p>
    1719     *
    1720     * @param matcher  the matcher to use to find the deletion, null causes no action
    1721     * @return this, to enable chaining
    1722     */
    1723    public StrBuilder deleteAll(final StrMatcher matcher) {
    1724        return replace(matcher, null, 0, size, -1);
    1725    }
    1726
    1727    /**
    1728     * Deletes the character at the specified index.
    1729     *
    1730     * @see #charAt(int)
    1731     * @see #setCharAt(int, char)
    1732     * @param index  the index to delete
    1733     * @return this, to enable chaining
    1734     * @throws IndexOutOfBoundsException if the index is invalid
    1735     */
    1736    public StrBuilder deleteCharAt(final int index) {
    1737        if (index < 0 || index >= size) {
    1738            throw new StringIndexOutOfBoundsException(index);
    1739        }
    1740        deleteImpl(index, index + 1, 1);
    1741        return this;
    1742    }
    1743
    1744    /**
    1745     * Deletes the character wherever it occurs in the builder.
    1746     *
    1747     * @param ch  the character to delete
    1748     * @return this, to enable chaining
    1749     */
    1750    public StrBuilder deleteFirst(final char ch) {
    1751        for (int i = 0; i < size; i++) {
    1752            if (buffer[i] == ch) {
    1753                deleteImpl(i, i + 1, 1);
    1754                break;
    1755            }
    1756        }
    1757        return this;
    1758    }
    1759
    1760    /**
    1761     * Deletes the string wherever it occurs in the builder.
    1762     *
    1763     * @param str  the string to delete, null causes no action
    1764     * @return this, to enable chaining
    1765     */
    1766    public StrBuilder deleteFirst(final String str) {
    1767        final int len = StringUtils.length(str);
    1768        if (len > 0) {
    1769            final int index = indexOf(str, 0);
    1770            if (index >= 0) {
    1771                deleteImpl(index, index + len, len);
    1772            }
    1773        }
    1774        return this;
    1775    }
    1776
    1777    /**
    1778     * Deletes the first match within the builder using the specified matcher.
    1779     * <p>
    1780     * Matchers can be used to perform advanced deletion behavior.
    1781     * For example you could write a matcher to delete
    1782     * where the character 'a' is followed by a number.
    1783     * </p>
    1784     *
    1785     * @param matcher  the matcher to use to find the deletion, null causes no action
    1786     * @return this, to enable chaining
    1787     */
    1788    public StrBuilder deleteFirst(final StrMatcher matcher) {
    1789        return replace(matcher, null, 0, size, 1);
    1790    }
    1791
    1792    /**
    1793     * Internal method to delete a range without validation.
    1794     *
    1795     * @param startIndex  the start index, must be valid
    1796     * @param endIndex  the end index (exclusive), must be valid
    1797     * @param len  the length, must be valid
    1798     * @throws IndexOutOfBoundsException if any index is invalid
    1799     */
    1800    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
    1801        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
    1802        size -= len;
    1803    }
    1804
    1805    /**
    1806     * Checks whether this builder ends with the specified string.
    1807     * <p>
    1808     * Note that this method handles null input quietly, unlike String.
    1809     * </p>
    1810     *
    1811     * @param str  the string to search for, null returns false
    1812     * @return true if the builder ends with the string
    1813     */
    1814    public boolean endsWith(final String str) {
    1815        if (str == null) {
    1816            return false;
    1817        }
    1818        final int len = str.length();
    1819        if (len == 0) {
    1820            return true;
    1821        }
    1822        if (len > size) {
    1823            return false;
    1824        }
    1825        int pos = size - len;
    1826        for (int i = 0; i < len; i++, pos++) {
    1827            if (buffer[pos] != str.charAt(i)) {
    1828                return false;
    1829            }
    1830        }
    1831        return true;
    1832    }
    1833
    1834    /**
    1835     * Checks the capacity and ensures that it is at least the size specified.
    1836     *
    1837     * @param capacity  the capacity to ensure
    1838     * @return this, to enable chaining
    1839     */
    1840    public StrBuilder ensureCapacity(final int capacity) {
    1841        if (capacity > buffer.length) {
    1842            buffer = ArrayUtils.arraycopy(buffer, 0, 0, size, () -> new char[capacity * 2]);
    1843        }
    1844        return this;
    1845    }
    1846
    1847    /**
    1848     * Checks the contents of this builder against another to see if they
    1849     * contain the same character content.
    1850     *
    1851     * @param obj  the object to check, null returns false
    1852     * @return true if the builders contain the same characters in the same order
    1853     */
    1854    @Override
    1855    public boolean equals(final Object obj) {
    1856        return obj instanceof StrBuilder && equals((StrBuilder) obj);
    1857    }
    1858
    1859    /**
    1860     * Checks the contents of this builder against another to see if they
    1861     * contain the same character content.
    1862     *
    1863     * @param other  the object to check, null returns false
    1864     * @return true if the builders contain the same characters in the same order
    1865     */
    1866    public boolean equals(final StrBuilder other) {
    1867        if (this == other) {
    1868            return true;
    1869        }
    1870        if (other == null) {
    1871            return false;
    1872        }
    1873        if (this.size != other.size) {
    1874            return false;
    1875        }
    1876        final char[] thisBuf = this.buffer;
    1877        final char[] otherBuf = other.buffer;
    1878        for (int i = size - 1; i >= 0; i--) {
    1879            if (thisBuf[i] != otherBuf[i]) {
    1880                return false;
    1881            }
    1882        }
    1883        return true;
    1884    }
    1885
    1886    /**
    1887     * Checks the contents of this builder against another to see if they
    1888     * contain the same character content ignoring case.
    1889     *
    1890     * @param other  the object to check, null returns false
    1891     * @return true if the builders contain the same characters in the same order
    1892     */
    1893    public boolean equalsIgnoreCase(final StrBuilder other) {
    1894        if (this == other) {
    1895            return true;
    1896        }
    1897        if (this.size != other.size) {
    1898            return false;
    1899        }
    1900        final char[] thisBuf = this.buffer;
    1901        final char[] otherBuf = other.buffer;
    1902        for (int i = size - 1; i >= 0; i--) {
    1903            final char c1 = thisBuf[i];
    1904            final char c2 = otherBuf[i];
    1905            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
    1906                return false;
    1907            }
    1908        }
    1909        return true;
    1910    }
    1911
    1912    /**
    1913     * Copies the character array into the specified array.
    1914     *
    1915     * @param destination  the destination array, null will cause an array to be created
    1916     * @return the input array, unless that was null or too small
    1917     */
    1918    public char[] getChars(char[] destination) {
    1919        final int len = length();
    1920        if (destination == null || destination.length < len) {
    1921            destination = new char[len];
    1922        }
    1923        return ArrayUtils.arraycopy(buffer, 0, destination, 0, len);
    1924    }
    1925
    1926    /**
    1927     * Copies the character array into the specified array.
    1928     *
    1929     * @param startIndex  first index to copy, inclusive, must be valid
    1930     * @param endIndex  last index, exclusive, must be valid
    1931     * @param destination  the destination array, must not be null or too small
    1932     * @param destinationIndex  the index to start copying in destination
    1933     * @throws NullPointerException if the array is null
    1934     * @throws IndexOutOfBoundsException if any index is invalid
    1935     */
    1936    public void getChars(final int startIndex, final int endIndex, final char[] destination, final int destinationIndex) {
    1937        if (startIndex < 0) {
    1938            throw new StringIndexOutOfBoundsException(startIndex);
    1939        }
    1940        if (endIndex < 0 || endIndex > length()) {
    1941            throw new StringIndexOutOfBoundsException(endIndex);
    1942        }
    1943        if (startIndex > endIndex) {
    1944            throw new StringIndexOutOfBoundsException("end < start");
    1945        }
    1946        System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
    1947    }
    1948
    1949    /**
    1950     * Gets the text to be appended when a {@link #appendNewLine() new line} is added.
    1951     *
    1952     * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
    1953     */
    1954    public String getNewLineText() {
    1955        return newLine;
    1956    }
    1957
    1958    /**
    1959     * Gets the text to be appended when null is added.
    1960     *
    1961     * @return the null text, null means no append
    1962     */
    1963    public String getNullText() {
    1964        return nullText;
    1965    }
    1966
    1967    /**
    1968     * Gets a suitable hash code for this builder.
    1969     *
    1970     * @return a hash code
    1971     */
    1972    @Override
    1973    public int hashCode() {
    1974        final char[] buf = buffer;
    1975        int hash = 0;
    1976        for (int i = size - 1; i >= 0; i--) {
    1977            hash = 31 * hash + buf[i];
    1978        }
    1979        return hash;
    1980    }
    1981
    1982    /**
    1983     * Searches the string builder to find the first reference to the specified char.
    1984     *
    1985     * @param ch  the character to find
    1986     * @return the first index of the character, or -1 if not found
    1987     */
    1988    public int indexOf(final char ch) {
    1989        return indexOf(ch, 0);
    1990    }
    1991
    1992    /**
    1993     * Searches the string builder to find the first reference to the specified char.
    1994     *
    1995     * @param ch  the character to find
    1996     * @param startIndex  the index to start at, invalid index rounded to edge
    1997     * @return the first index of the character, or -1 if not found
    1998     */
    1999    public int indexOf(final char ch, int startIndex) {
    2000        startIndex = Math.max(startIndex, 0);
    2001        if (startIndex >= size) {
    2002            return -1;
    2003        }
    2004        final char[] thisBuf = buffer;
    2005        for (int i = startIndex; i < size; i++) {
    2006            if (thisBuf[i] == ch) {
    2007                return i;
    2008            }
    2009        }
    2010        return -1;
    2011    }
    2012
    2013    /**
    2014     * Searches the string builder to find the first reference to the specified string.
    2015     * <p>
    2016     * Note that a null input string will return -1, whereas the JDK throws an exception.
    2017     * </p>
    2018     *
    2019     * @param str  the string to find, null returns -1
    2020     * @return the first index of the string, or -1 if not found
    2021     */
    2022    public int indexOf(final String str) {
    2023        return indexOf(str, 0);
    2024    }
    2025
    2026    /**
    2027     * Searches the string builder to find the first reference to the specified
    2028     * string starting searching from the given index.
    2029     * <p>
    2030     * Note that a null input string will return -1, whereas the JDK throws an exception.
    2031     * </p>
    2032     *
    2033     * @param str  the string to find, null returns -1
    2034     * @param startIndex  the index to start at, invalid index rounded to edge
    2035     * @return the first index of the string, or -1 if not found
    2036     */
    2037    public int indexOf(final String str, final int startIndex) {
    2038        return StringUtils.indexOf(this, str, startIndex);
    2039    }
    2040
    2041    /**
    2042     * Searches the string builder using the matcher to find the first match.
    2043     * <p>
    2044     * Matchers can be used to perform advanced searching behavior.
    2045     * For example you could write a matcher to find the character 'a'
    2046     * followed by a number.
    2047     * </p>
    2048     *
    2049     * @param matcher  the matcher to use, null returns -1
    2050     * @return the first index matched, or -1 if not found
    2051     */
    2052    public int indexOf(final StrMatcher matcher) {
    2053        return indexOf(matcher, 0);
    2054    }
    2055
    2056    /**
    2057     * Searches the string builder using the matcher to find the first
    2058     * match searching from the given index.
    2059     * <p>
    2060     * Matchers can be used to perform advanced searching behavior.
    2061     * For example you could write a matcher to find the character 'a'
    2062     * followed by a number.
    2063     * </p>
    2064     *
    2065     * @param matcher  the matcher to use, null returns -1
    2066     * @param startIndex  the index to start at, invalid index rounded to edge
    2067     * @return the first index matched, or -1 if not found
    2068     */
    2069    public int indexOf(final StrMatcher matcher, int startIndex) {
    2070        startIndex = Math.max(startIndex, 0);
    2071        if (matcher == null || startIndex >= size) {
    2072            return -1;
    2073        }
    2074        final int len = size;
    2075        final char[] buf = buffer;
    2076        for (int i = startIndex; i < len; i++) {
    2077            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
    2078                return i;
    2079            }
    2080        }
    2081        return -1;
    2082    }
    2083
    2084    /**
    2085     * Inserts the value into this builder.
    2086     *
    2087     * @param index  the index to add at, must be valid
    2088     * @param value  the value to insert
    2089     * @return this, to enable chaining
    2090     * @throws IndexOutOfBoundsException if the index is invalid
    2091     */
    2092    public StrBuilder insert(int index, final boolean value) {
    2093        validateIndex(index);
    2094        if (value) {
    2095            ensureCapacity(size + 4);
    2096            System.arraycopy(buffer, index, buffer, index + 4, size - index);
    2097            buffer[index++] = 't';
    2098            buffer[index++] = 'r';
    2099            buffer[index++] = 'u';
    2100            buffer[index] = 'e';
    2101            size += 4;
    2102        } else {
    2103            ensureCapacity(size + 5);
    2104            System.arraycopy(buffer, index, buffer, index + 5, size - index);
    2105            buffer[index++] = 'f';
    2106            buffer[index++] = 'a';
    2107            buffer[index++] = 'l';
    2108            buffer[index++] = 's';
    2109            buffer[index] = 'e';
    2110            size += 5;
    2111        }
    2112        return this;
    2113    }
    2114
    2115    /**
    2116     * Inserts the value into this builder.
    2117     *
    2118     * @param index  the index to add at, must be valid
    2119     * @param value  the value to insert
    2120     * @return this, to enable chaining
    2121     * @throws IndexOutOfBoundsException if the index is invalid
    2122     */
    2123    public StrBuilder insert(final int index, final char value) {
    2124        validateIndex(index);
    2125        ensureCapacity(size + 1);
    2126        System.arraycopy(buffer, index, buffer, index + 1, size - index);
    2127        buffer[index] = value;
    2128        size++;
    2129        return this;
    2130    }
    2131
    2132    /**
    2133     * Inserts the character array into this builder.
    2134     * Inserting null will use the stored null text value.
    2135     *
    2136     * @param index  the index to add at, must be valid
    2137     * @param chars  the char array to insert
    2138     * @return this, to enable chaining
    2139     * @throws IndexOutOfBoundsException if the index is invalid
    2140     */
    2141    public StrBuilder insert(final int index, final char[] chars) {
    2142        validateIndex(index);
    2143        if (chars == null) {
    2144            return insert(index, nullText);
    2145        }
    2146        final int len = chars.length;
    2147        if (len > 0) {
    2148            ensureCapacity(size + len);
    2149            System.arraycopy(buffer, index, buffer, index + len, size - index);
    2150            System.arraycopy(chars, 0, buffer, index, len);
    2151            size += len;
    2152        }
    2153        return this;
    2154    }
    2155
    2156    /**
    2157     * Inserts part of the character array into this builder.
    2158     * Inserting null will use the stored null text value.
    2159     *
    2160     * @param index  the index to add at, must be valid
    2161     * @param chars  the char array to insert
    2162     * @param offset  the offset into the character array to start at, must be valid
    2163     * @param length  the length of the character array part to copy, must be positive
    2164     * @return this, to enable chaining
    2165     * @throws IndexOutOfBoundsException if any index is invalid
    2166     */
    2167    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
    2168        validateIndex(index);
    2169        if (chars == null) {
    2170            return insert(index, nullText);
    2171        }
    2172        if (offset < 0 || offset > chars.length) {
    2173            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
    2174        }
    2175        if (length < 0 || offset + length > chars.length) {
    2176            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
    2177        }
    2178        if (length > 0) {
    2179            ensureCapacity(size + length);
    2180            System.arraycopy(buffer, index, buffer, index + length, size - index);
    2181            System.arraycopy(chars, offset, buffer, index, length);
    2182            size += length;
    2183        }
    2184        return this;
    2185    }
    2186
    2187    /**
    2188     * Inserts the value into this builder.
    2189     *
    2190     * @param index  the index to add at, must be valid
    2191     * @param value  the value to insert
    2192     * @return this, to enable chaining
    2193     * @throws IndexOutOfBoundsException if the index is invalid
    2194     */
    2195    public StrBuilder insert(final int index, final double value) {
    2196        return insert(index, String.valueOf(value));
    2197    }
    2198
    2199    /**
    2200     * Inserts the value into this builder.
    2201     *
    2202     * @param index  the index to add at, must be valid
    2203     * @param value  the value to insert
    2204     * @return this, to enable chaining
    2205     * @throws IndexOutOfBoundsException if the index is invalid
    2206     */
    2207    public StrBuilder insert(final int index, final float value) {
    2208        return insert(index, String.valueOf(value));
    2209    }
    2210
    2211    /**
    2212     * Inserts the value into this builder.
    2213     *
    2214     * @param index  the index to add at, must be valid
    2215     * @param value  the value to insert
    2216     * @return this, to enable chaining
    2217     * @throws IndexOutOfBoundsException if the index is invalid
    2218     */
    2219    public StrBuilder insert(final int index, final int value) {
    2220        return insert(index, String.valueOf(value));
    2221    }
    2222
    2223    /**
    2224     * Inserts the value into this builder.
    2225     *
    2226     * @param index  the index to add at, must be valid
    2227     * @param value  the value to insert
    2228     * @return this, to enable chaining
    2229     * @throws IndexOutOfBoundsException if the index is invalid
    2230     */
    2231    public StrBuilder insert(final int index, final long value) {
    2232        return insert(index, String.valueOf(value));
    2233    }
    2234
    2235    /**
    2236     * Inserts the string representation of an object into this builder.
    2237     * Inserting null will use the stored null text value.
    2238     *
    2239     * @param index  the index to add at, must be valid
    2240     * @param obj  the object to insert
    2241     * @return this, to enable chaining
    2242     * @throws IndexOutOfBoundsException if the index is invalid
    2243     */
    2244    public StrBuilder insert(final int index, final Object obj) {
    2245        if (obj == null) {
    2246            return insert(index, nullText);
    2247        }
    2248        return insert(index, obj.toString());
    2249    }
    2250
    2251    /**
    2252     * Inserts the string into this builder.
    2253     * Inserting null will use the stored null text value.
    2254     *
    2255     * @param index  the index to add at, must be valid
    2256     * @param str  the string to insert
    2257     * @return this, to enable chaining
    2258     * @throws IndexOutOfBoundsException if the index is invalid
    2259     */
    2260    public StrBuilder insert(final int index, String str) {
    2261        validateIndex(index);
    2262        if (str == null) {
    2263            str = nullText;
    2264        }
    2265        if (str != null) {
    2266            final int strLen = str.length();
    2267            if (strLen > 0) {
    2268                final int newSize = size + strLen;
    2269                ensureCapacity(newSize);
    2270                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
    2271                size = newSize;
    2272                str.getChars(0, strLen, buffer, index);
    2273            }
    2274        }
    2275        return this;
    2276    }
    2277
    2278    /**
    2279     * Checks is the string builder is empty (convenience Collections API style method).
    2280     * <p>
    2281     * This method is the same as checking {@link #length()} and is provided to match the
    2282     * API of Collections.
    2283     * </p>
    2284     *
    2285     * @return {@code true} if the size is {@code 0}.
    2286     */
    2287    public boolean isEmpty() {
    2288        return size == 0;
    2289    }
    2290
    2291    /**
    2292     * Checks is the string builder is not empty (convenience Collections API style method).
    2293     * <p>
    2294     * This method is the same as checking {@link #length()} and is provided to match the
    2295     * API of Collections.
    2296     * </p>
    2297     *
    2298     * @return {@code true} if the size is greater than {@code 0}.
    2299     * @since 3.12.0
    2300     */
    2301    public boolean isNotEmpty() {
    2302        return size > 0;
    2303    }
    2304
    2305    /**
    2306     * Searches the string builder to find the last reference to the specified char.
    2307     *
    2308     * @param ch  the character to find
    2309     * @return the last index of the character, or -1 if not found
    2310     */
    2311    public int lastIndexOf(final char ch) {
    2312        return lastIndexOf(ch, size - 1);
    2313    }
    2314
    2315    /**
    2316     * Searches the string builder to find the last reference to the specified char.
    2317     *
    2318     * @param ch  the character to find
    2319     * @param startIndex  the index to start at, invalid index rounded to edge
    2320     * @return the last index of the character, or -1 if not found
    2321     */
    2322    public int lastIndexOf(final char ch, int startIndex) {
    2323        startIndex = startIndex >= size ? size - 1 : startIndex;
    2324        if (startIndex < 0) {
    2325            return -1;
    2326        }
    2327        for (int i = startIndex; i >= 0; i--) {
    2328            if (buffer[i] == ch) {
    2329                return i;
    2330            }
    2331        }
    2332        return -1;
    2333    }
    2334
    2335    /**
    2336     * Searches the string builder to find the last reference to the specified string.
    2337     * <p>
    2338     * Note that a null input string will return -1, whereas the JDK throws an exception.
    2339     * </p>
    2340     *
    2341     * @param str  the string to find, null returns -1
    2342     * @return the last index of the string, or -1 if not found
    2343     */
    2344    public int lastIndexOf(final String str) {
    2345        return lastIndexOf(str, size - 1);
    2346    }
    2347
    2348    /**
    2349     * Searches the string builder to find the last reference to the specified
    2350     * string starting searching from the given index.
    2351     * <p>
    2352     * Note that a null input string will return -1, whereas the JDK throws an exception.
    2353     * </p>
    2354     *
    2355     * @param str  the string to find, null returns -1
    2356     * @param startIndex  the index to start at, invalid index rounded to edge
    2357     * @return the last index of the string, or -1 if not found
    2358     */
    2359    public int lastIndexOf(final String str, final int startIndex) {
    2360        return StringUtils.lastIndexOf(this, str, startIndex);
    2361    }
    2362
    2363    /**
    2364     * Searches the string builder using the matcher to find the last match.
    2365     * <p>
    2366     * Matchers can be used to perform advanced searching behavior.
    2367     * For example you could write a matcher to find the character 'a'
    2368     * followed by a number.
    2369     * </p>
    2370     *
    2371     * @param matcher  the matcher to use, null returns -1
    2372     * @return the last index matched, or -1 if not found
    2373     */
    2374    public int lastIndexOf(final StrMatcher matcher) {
    2375        return lastIndexOf(matcher, size);
    2376    }
    2377
    2378    /**
    2379     * Searches the string builder using the matcher to find the last
    2380     * match searching from the given index.
    2381     * <p>
    2382     * Matchers can be used to perform advanced searching behavior.
    2383     * For example you could write a matcher to find the character 'a'
    2384     * followed by a number.
    2385     * </p>
    2386     *
    2387     * @param matcher  the matcher to use, null returns -1
    2388     * @param startIndex  the index to start at, invalid index rounded to edge
    2389     * @return the last index matched, or -1 if not found
    2390     */
    2391    public int lastIndexOf(final StrMatcher matcher, int startIndex) {
    2392        startIndex = startIndex >= size ? size - 1 : startIndex;
    2393        if (matcher == null || startIndex < 0) {
    2394            return -1;
    2395        }
    2396        final char[] buf = buffer;
    2397        final int endIndex = startIndex + 1;
    2398        for (int i = startIndex; i >= 0; i--) {
    2399            if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
    2400                return i;
    2401            }
    2402        }
    2403        return -1;
    2404    }
    2405
    2406    /**
    2407     * Extracts the leftmost characters from the string builder without
    2408     * throwing an exception.
    2409     * <p>
    2410     * This method extracts the left {@code length} characters from
    2411     * the builder. If this many characters are not available, the whole
    2412     * builder is returned. Thus the returned string may be shorter than the
    2413     * length requested.
    2414     * </p>
    2415     *
    2416     * @param length  the number of characters to extract, negative returns empty string
    2417     * @return the new string
    2418     */
    2419    public String leftString(final int length) {
    2420        if (length <= 0) {
    2421            return StringUtils.EMPTY;
    2422        }
    2423        if (length >= size) {
    2424            return new String(buffer, 0, size);
    2425        }
    2426        return new String(buffer, 0, length);
    2427    }
    2428
    2429    /**
    2430     * Gets the length of the string builder.
    2431     *
    2432     * @return the length
    2433     */
    2434    @Override
    2435    public int length() {
    2436        return size;
    2437    }
    2438
    2439    /**
    2440     * Extracts some characters from the middle of the string builder without
    2441     * throwing an exception.
    2442     * <p>
    2443     * This method extracts {@code length} characters from the builder
    2444     * at the specified index.
    2445     * If the index is negative it is treated as zero.
    2446     * If the index is greater than the builder size, it is treated as the builder size.
    2447     * If the length is negative, the empty string is returned.
    2448     * If insufficient characters are available in the builder, as much as possible is returned.
    2449     * Thus the returned string may be shorter than the length requested.
    2450     * </p>
    2451     *
    2452     * @param index  the index to start at, negative means zero
    2453     * @param length  the number of characters to extract, negative returns empty string
    2454     * @return the new string
    2455     */
    2456    public String midString(int index, final int length) {
    2457        if (index < 0) {
    2458            index = 0;
    2459        }
    2460        if (length <= 0 || index >= size) {
    2461            return StringUtils.EMPTY;
    2462        }
    2463        if (size <= index + length) {
    2464            return new String(buffer, index, size - index);
    2465        }
    2466        return new String(buffer, index, length);
    2467    }
    2468
    2469    /**
    2470     * Minimizes the capacity to the actual length of the string.
    2471     *
    2472     * @return this, to enable chaining
    2473     */
    2474    public StrBuilder minimizeCapacity() {
    2475        if (buffer.length > length()) {
    2476            buffer = ArrayUtils.arraycopy(buffer, 0, 0, size, () -> new char[length()]);
    2477        }
    2478        return this;
    2479    }
    2480
    2481    /**
    2482     * If possible, reads chars from the provided {@link Readable} directly into underlying
    2483     * character buffer without making extra copies.
    2484     *
    2485     * @param readable  object to read from
    2486     * @return the number of characters read
    2487     * @throws IOException if an I/O error occurs.
    2488     *
    2489     * @since 3.4
    2490     * @see #appendTo(Appendable)
    2491     */
    2492    public int readFrom(final Readable readable) throws IOException {
    2493        final int oldSize = size;
    2494        if (readable instanceof Reader) {
    2495            final Reader r = (Reader) readable;
    2496            ensureCapacity(size + 1);
    2497            int read;
    2498            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
    2499                size += read;
    2500                ensureCapacity(size + 1);
    2501            }
    2502        } else if (readable instanceof CharBuffer) {
    2503            final CharBuffer cb = (CharBuffer) readable;
    2504            final int remaining = cb.remaining();
    2505            ensureCapacity(size + remaining);
    2506            cb.get(buffer, size, remaining);
    2507            size += remaining;
    2508        } else {
    2509            while (true) {
    2510                ensureCapacity(size + 1);
    2511                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
    2512                final int read = readable.read(buf);
    2513                if (read == -1) {
    2514                    break;
    2515                }
    2516                size += read;
    2517            }
    2518        }
    2519        return size - oldSize;
    2520    }
    2521
    2522    /**
    2523     * Replaces a portion of the string builder with another string.
    2524     * The length of the inserted string does not have to match the removed length.
    2525     *
    2526     * @param startIndex  the start index, inclusive, must be valid
    2527     * @param endIndex  the end index, exclusive, must be valid except
    2528     *  that if too large it is treated as end of string
    2529     * @param replaceStr  the string to replace with, null means delete range
    2530     * @return this, to enable chaining
    2531     * @throws IndexOutOfBoundsException if the index is invalid
    2532     */
    2533    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
    2534        endIndex = validateRange(startIndex, endIndex);
    2535        final int insertLen = StringUtils.length(replaceStr);
    2536        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
    2537        return this;
    2538    }
    2539
    2540    /**
    2541     * Advanced search and replaces within the builder using a matcher.
    2542     * <p>
    2543     * Matchers can be used to perform advanced behavior.
    2544     * For example you could write a matcher to delete all occurrences
    2545     * where the character 'a' is followed by a number.
    2546     * </p>
    2547     *
    2548     * @param matcher  the matcher to use to find the deletion, null causes no action
    2549     * @param replaceStr  the string to replace the match with, null is a delete
    2550     * @param startIndex  the start index, inclusive, must be valid
    2551     * @param endIndex  the end index, exclusive, must be valid except
    2552     *  that if too large it is treated as end of string
    2553     * @param replaceCount  the number of times to replace, -1 for replace all
    2554     * @return this, to enable chaining
    2555     * @throws IndexOutOfBoundsException if start index is invalid
    2556     */
    2557    public StrBuilder replace(
    2558            final StrMatcher matcher, final String replaceStr,
    2559            final int startIndex, int endIndex, final int replaceCount) {
    2560        endIndex = validateRange(startIndex, endIndex);
    2561        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
    2562    }
    2563
    2564    /**
    2565     * Replaces the search character with the replace character
    2566     * throughout the builder.
    2567     *
    2568     * @param search  the search character
    2569     * @param replace  the replace character
    2570     * @return this, to enable chaining
    2571     */
    2572    public StrBuilder replaceAll(final char search, final char replace) {
    2573        if (search != replace) {
    2574            for (int i = 0; i < size; i++) {
    2575                if (buffer[i] == search) {
    2576                    buffer[i] = replace;
    2577                }
    2578            }
    2579        }
    2580        return this;
    2581    }
    2582
    2583    /**
    2584     * Replaces the search string with the replace string throughout the builder.
    2585     *
    2586     * @param searchStr  the search string, null causes no action to occur
    2587     * @param replaceStr  the replace string, null is equivalent to an empty string
    2588     * @return this, to enable chaining
    2589     */
    2590    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
    2591        final int searchLen = StringUtils.length(searchStr);
    2592        if (searchLen > 0) {
    2593            final int replaceLen = StringUtils.length(replaceStr);
    2594            int index = indexOf(searchStr, 0);
    2595            while (index >= 0) {
    2596                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
    2597                index = indexOf(searchStr, index + replaceLen);
    2598            }
    2599        }
    2600        return this;
    2601    }
    2602
    2603    /**
    2604     * Replaces all matches within the builder with the replace string.
    2605     * <p>
    2606     * Matchers can be used to perform advanced replace behavior.
    2607     * For example you could write a matcher to replace all occurrences
    2608     * where the character 'a' is followed by a number.
    2609     * </p>
    2610     *
    2611     * @param matcher  the matcher to use to find the deletion, null causes no action
    2612     * @param replaceStr  the replace string, null is equivalent to an empty string
    2613     * @return this, to enable chaining
    2614     */
    2615    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
    2616        return replace(matcher, replaceStr, 0, size, -1);
    2617    }
    2618
    2619    /**
    2620     * Replaces the first instance of the search character with the
    2621     * replace character in the builder.
    2622     *
    2623     * @param search  the search character
    2624     * @param replace  the replace character
    2625     * @return this, to enable chaining
    2626     */
    2627    public StrBuilder replaceFirst(final char search, final char replace) {
    2628        if (search != replace) {
    2629            for (int i = 0; i < size; i++) {
    2630                if (buffer[i] == search) {
    2631                    buffer[i] = replace;
    2632                    break;
    2633                }
    2634            }
    2635        }
    2636        return this;
    2637    }
    2638
    2639    /**
    2640     * Replaces the first instance of the search string with the replace string.
    2641     *
    2642     * @param searchStr  the search string, null causes no action to occur
    2643     * @param replaceStr  the replace string, null is equivalent to an empty string
    2644     * @return this, to enable chaining
    2645     */
    2646    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
    2647        final int searchLen = StringUtils.length(searchStr);
    2648        if (searchLen > 0) {
    2649            final int index = indexOf(searchStr, 0);
    2650            if (index >= 0) {
    2651                final int replaceLen = StringUtils.length(replaceStr);
    2652                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
    2653            }
    2654        }
    2655        return this;
    2656    }
    2657
    2658    /**
    2659     * Replaces the first match within the builder with the replace string.
    2660     * <p>
    2661     * Matchers can be used to perform advanced replace behavior.
    2662     * For example you could write a matcher to replace
    2663     * where the character 'a' is followed by a number.
    2664     * </p>
    2665     *
    2666     * @param matcher  the matcher to use to find the deletion, null causes no action
    2667     * @param replaceStr  the replace string, null is equivalent to an empty string
    2668     * @return this, to enable chaining
    2669     */
    2670    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
    2671        return replace(matcher, replaceStr, 0, size, 1);
    2672    }
    2673
    2674    /**
    2675     * Internal method to delete a range without validation.
    2676     *
    2677     * @param startIndex  the start index, must be valid
    2678     * @param endIndex  the end index (exclusive), must be valid
    2679     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
    2680     * @param insertStr  the string to replace with, null means delete range
    2681     * @param insertLen  the length of the insert string, must be valid
    2682     * @throws IndexOutOfBoundsException if any index is invalid
    2683     */
    2684    private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
    2685        final int newSize = size - removeLen + insertLen;
    2686        if (insertLen != removeLen) {
    2687            ensureCapacity(newSize);
    2688            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
    2689            size = newSize;
    2690        }
    2691        if (insertLen > 0) {
    2692            insertStr.getChars(0, insertLen, buffer, startIndex);
    2693        }
    2694    }
    2695
    2696    /**
    2697     * Replaces within the builder using a matcher.
    2698     * <p>
    2699     * Matchers can be used to perform advanced behavior.
    2700     * For example you could write a matcher to delete all occurrences
    2701     * where the character 'a' is followed by a number.
    2702     * </p>
    2703     *
    2704     * @param matcher  the matcher to use to find the deletion, null causes no action
    2705     * @param replaceStr  the string to replace the match with, null is a delete
    2706     * @param from  the start index, must be valid
    2707     * @param to  the end index (exclusive), must be valid
    2708     * @param replaceCount  the number of times to replace, -1 for replace all
    2709     * @return this, to enable chaining
    2710     * @throws IndexOutOfBoundsException if any index is invalid
    2711     */
    2712    private StrBuilder replaceImpl(
    2713            final StrMatcher matcher, final String replaceStr,
    2714            final int from, int to, int replaceCount) {
    2715        if (matcher == null || size == 0) {
    2716            return this;
    2717        }
    2718        final int replaceLen = StringUtils.length(replaceStr);
    2719        for (int i = from; i < to && replaceCount != 0; i++) {
    2720            final char[] buf = buffer;
    2721            final int removeLen = matcher.isMatch(buf, i, from, to);
    2722            if (removeLen > 0) {
    2723                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
    2724                to = to - removeLen + replaceLen;
    2725                i = i + replaceLen - 1;
    2726                if (replaceCount > 0) {
    2727                    replaceCount--;
    2728                }
    2729            }
    2730        }
    2731        return this;
    2732    }
    2733
    2734    /**
    2735     * Reverses the string builder placing each character in the opposite index.
    2736     *
    2737     * @return this, to enable chaining
    2738     */
    2739    public StrBuilder reverse() {
    2740        if (size == 0) {
    2741            return this;
    2742        }
    2743
    2744        final int half = size / 2;
    2745        final char[] buf = buffer;
    2746        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
    2747            final char swap = buf[leftIdx];
    2748            buf[leftIdx] = buf[rightIdx];
    2749            buf[rightIdx] = swap;
    2750        }
    2751        return this;
    2752    }
    2753
    2754    /**
    2755     * Extracts the rightmost characters from the string builder without
    2756     * throwing an exception.
    2757     * <p>
    2758     * This method extracts the right {@code length} characters from
    2759     * the builder. If this many characters are not available, the whole
    2760     * builder is returned. Thus the returned string may be shorter than the
    2761     * length requested.
    2762     * </p>
    2763     *
    2764     * @param length  the number of characters to extract, negative returns empty string
    2765     * @return the new string
    2766     */
    2767    public String rightString(final int length) {
    2768        if (length <= 0) {
    2769            return StringUtils.EMPTY;
    2770        }
    2771        if (length >= size) {
    2772            return new String(buffer, 0, size);
    2773        }
    2774        return new String(buffer, size - length, length);
    2775    }
    2776
    2777    /**
    2778     * Sets the character at the specified index.
    2779     *
    2780     * @see #charAt(int)
    2781     * @see #deleteCharAt(int)
    2782     * @param index  the index to set
    2783     * @param ch  the new character
    2784     * @return this, to enable chaining
    2785     * @throws IndexOutOfBoundsException if the index is invalid
    2786     */
    2787    public StrBuilder setCharAt(final int index, final char ch) {
    2788        if (index < 0 || index >= length()) {
    2789            throw new StringIndexOutOfBoundsException(index);
    2790        }
    2791        buffer[index] = ch;
    2792        return this;
    2793    }
    2794
    2795    /**
    2796     * Updates the length of the builder by either dropping the last characters
    2797     * or adding filler of Unicode zero.
    2798     *
    2799     * @param length  the length to set to, must be zero or positive
    2800     * @return this, to enable chaining
    2801     * @throws IndexOutOfBoundsException if the length is negative
    2802     */
    2803    public StrBuilder setLength(final int length) {
    2804        if (length < 0) {
    2805            throw new StringIndexOutOfBoundsException(length);
    2806        }
    2807        if (length < size) {
    2808            size = length;
    2809        } else if (length > size) {
    2810            ensureCapacity(length);
    2811            final int oldEnd = size;
    2812            size = length;
    2813            for (int i = oldEnd; i < length; i++) {
    2814                buffer[i] = CharUtils.NUL;
    2815            }
    2816        }
    2817        return this;
    2818    }
    2819
    2820    /**
    2821     * Sets the text to be appended when {@link #appendNewLine() new line} is called.
    2822     *
    2823     * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
    2824     * @return {@code this} instance.
    2825     */
    2826    public StrBuilder setNewLineText(final String newLine) {
    2827        this.newLine = newLine;
    2828        return this;
    2829    }
    2830
    2831    /**
    2832     * Sets the text to be appended when null is added.
    2833     *
    2834     * @param nullText  the null text, null means no append
    2835     * @return this, to enable chaining
    2836     */
    2837    public StrBuilder setNullText(String nullText) {
    2838        if (StringUtils.isEmpty(nullText)) {
    2839            nullText = null;
    2840        }
    2841        this.nullText = nullText;
    2842        return this;
    2843    }
    2844
    2845    /**
    2846     * Gets the length of the string builder.
    2847     * <p>
    2848     * This method is the same as {@link #length()} and is provided to match the
    2849     * API of Collections.
    2850     * </p>
    2851     *
    2852     * @return the length
    2853     */
    2854    public int size() {
    2855        return size;
    2856    }
    2857
    2858    /**
    2859     * Checks whether this builder starts with the specified string.
    2860     * <p>
    2861     * Note that this method handles null input quietly, unlike String.
    2862     * </p>
    2863     *
    2864     * @param str  the string to search for, null returns false
    2865     * @return true if the builder starts with the string
    2866     */
    2867    public boolean startsWith(final String str) {
    2868        if (str == null) {
    2869            return false;
    2870        }
    2871        final int len = str.length();
    2872        if (len == 0) {
    2873            return true;
    2874        }
    2875        if (len > size) {
    2876            return false;
    2877        }
    2878        for (int i = 0; i < len; i++) {
    2879            if (buffer[i] != str.charAt(i)) {
    2880                return false;
    2881            }
    2882        }
    2883        return true;
    2884    }
    2885
    2886    /**
    2887     * {@inheritDoc}
    2888     * @since 3.0
    2889     */
    2890    @Override
    2891    public CharSequence subSequence(final int startIndex, final int endIndex) {
    2892      if (startIndex < 0) {
    2893          throw new StringIndexOutOfBoundsException(startIndex);
    2894      }
    2895      if (endIndex > size) {
    2896          throw new StringIndexOutOfBoundsException(endIndex);
    2897      }
    2898      if (startIndex > endIndex) {
    2899          throw new StringIndexOutOfBoundsException(endIndex - startIndex);
    2900      }
    2901      return substring(startIndex, endIndex);
    2902    }
    2903
    2904    /**
    2905     * Extracts a portion of this string builder as a string.
    2906     *
    2907     * @param start  the start index, inclusive, must be valid
    2908     * @return the new string
    2909     * @throws IndexOutOfBoundsException if the index is invalid
    2910     */
    2911    public String substring(final int start) {
    2912        return substring(start, size);
    2913    }
    2914
    2915    /**
    2916     * Extracts a portion of this string builder as a string.
    2917     * <p>
    2918     * Note: This method treats an endIndex greater than the length of the
    2919     * builder as equal to the length of the builder, and continues
    2920     * without error, unlike StringBuffer or String.
    2921     * </p>
    2922     *
    2923     * @param startIndex  the start index, inclusive, must be valid
    2924     * @param endIndex  the end index, exclusive, must be valid except
    2925     *  that if too large it is treated as end of string
    2926     * @return the new string
    2927     * @throws IndexOutOfBoundsException if the index is invalid
    2928     */
    2929    public String substring(final int startIndex, int endIndex) {
    2930        endIndex = validateRange(startIndex, endIndex);
    2931        return new String(buffer, startIndex, endIndex - startIndex);
    2932    }
    2933
    2934    /**
    2935     * Copies the builder's character array into a new character array.
    2936     *
    2937     * @return a new array that represents the contents of the builder
    2938     */
    2939    public char[] toCharArray() {
    2940        if (size == 0) {
    2941            return ArrayUtils.EMPTY_CHAR_ARRAY;
    2942        }
    2943        return ArrayUtils.arraycopy(buffer, 0, 0, size, char[]::new);
    2944    }
    2945
    2946    /**
    2947     * Copies part of the builder's character array into a new character array.
    2948     *
    2949     * @param startIndex  the start index, inclusive, must be valid
    2950     * @param endIndex  the end index, exclusive, must be valid except that
    2951     *  if too large it is treated as end of string
    2952     * @return a new array that holds part of the contents of the builder
    2953     * @throws IndexOutOfBoundsException if startIndex is invalid,
    2954     *  or if endIndex is invalid (but endIndex greater than size is valid)
    2955     */
    2956    public char[] toCharArray(final int startIndex, int endIndex) {
    2957        endIndex = validateRange(startIndex, endIndex);
    2958        final int len = endIndex - startIndex;
    2959        if (len == 0) {
    2960            return ArrayUtils.EMPTY_CHAR_ARRAY;
    2961        }
    2962        return ArrayUtils.arraycopy(buffer, startIndex, 0, len, char[]::new);
    2963    }
    2964
    2965    /**
    2966     * Gets a String version of the string builder, creating a new instance
    2967     * each time the method is called.
    2968     * <p>
    2969     * Note that unlike StringBuffer, the string version returned is
    2970     * independent of the string builder.
    2971     * </p>
    2972     *
    2973     * @return the builder as a String
    2974     */
    2975    @Override
    2976    public String toString() {
    2977        return new String(buffer, 0, size);
    2978    }
    2979
    2980    /**
    2981     * Gets a StringBuffer version of the string builder, creating a
    2982     * new instance each time the method is called.
    2983     *
    2984     * @return the builder as a StringBuffer
    2985     */
    2986    public StringBuffer toStringBuffer() {
    2987        return new StringBuffer(size).append(buffer, 0, size);
    2988    }
    2989
    2990    /**
    2991     * Gets a StringBuilder version of the string builder, creating a
    2992     * new instance each time the method is called.
    2993     *
    2994     * @return the builder as a StringBuilder
    2995     * @since 3.2
    2996     */
    2997    public StringBuilder toStringBuilder() {
    2998        return new StringBuilder(size).append(buffer, 0, size);
    2999    }
    3000
    3001    /**
    3002     * Trims the builder by removing characters less than or equal to a space
    3003     * from the beginning and end.
    3004     *
    3005     * @return this, to enable chaining
    3006     */
    3007    public StrBuilder trim() {
    3008        if (size == 0) {
    3009            return this;
    3010        }
    3011        int len = size;
    3012        final char[] buf = buffer;
    3013        int pos = 0;
    3014        while (pos < len && buf[pos] <= ' ') {
    3015            pos++;
    3016        }
    3017        while (pos < len && buf[len - 1] <= ' ') {
    3018            len--;
    3019        }
    3020        if (len < size) {
    3021            delete(len, size);
    3022        }
    3023        if (pos > 0) {
    3024            delete(0, pos);
    3025        }
    3026        return this;
    3027    }
    3028
    3029    /**
    3030     * Validates parameters defining a single index in the builder.
    3031     *
    3032     * @param index  the index, must be valid
    3033     * @throws IndexOutOfBoundsException if the index is invalid
    3034     */
    3035    protected void validateIndex(final int index) {
    3036        if (index < 0 || index > size) {
    3037            throw new StringIndexOutOfBoundsException(index);
    3038        }
    3039    }
    3040
    3041    /**
    3042     * Validates parameters defining a range of the builder.
    3043     *
    3044     * @param startIndex  the start index, inclusive, must be valid
    3045     * @param endIndex  the end index, exclusive, must be valid except
    3046     *  that if too large it is treated as end of string
    3047     * @return the new string
    3048     * @throws IndexOutOfBoundsException if the index is invalid
    3049     */
    3050    protected int validateRange(final int startIndex, int endIndex) {
    3051        if (startIndex < 0) {
    3052            throw new StringIndexOutOfBoundsException(startIndex);
    3053        }
    3054        if (endIndex > size) {
    3055            endIndex = size;
    3056        }
    3057        if (startIndex > endIndex) {
    3058            throw new StringIndexOutOfBoundsException("end < start");
    3059        }
    3060        return endIndex;
    3061    }
    3062
    3063}