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