diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 09450c2c0a2..0ff07c862df 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -621,9 +621,11 @@ public static String center(String str, final int size, final char padChar) { if (pads <= 0) { return str; } - str = leftPad(str, strLen + pads / 2, padChar); - str = rightPad(str, size, padChar); - return str; + StringBuilder stringBuilder = new StringBuilder(size); + repeat(stringBuilder, padChar, pads / 2); + stringBuilder.append(str); + repeat(stringBuilder, padChar, size - (strLen + pads / 2)); + return stringBuilder.toString(); } /** @@ -6253,6 +6255,23 @@ public static String repeat(final char ch, final int repeat) { return new String(buf); } + /** + *

Make the padding using the specified delimiter repeated + * to a given length, and fill the result to a StringBuilder

+ * + * This function works like {@code stringBuilder.append(repeat(ch,repeat))}, but runs faster. + * + * @param stringBuilder stringBuilder to fill + * @param ch character to repeat + * @param repeat number of times to repeat char, negative treated as zero + * @see #repeat(char, int) + */ + static void repeat(StringBuilder stringBuilder, final char ch, final int repeat) { + for (int i = repeat - 1; i >= 0; i--) { + stringBuilder.append(ch); + } + } + /** *

Repeat a String {@code repeat} times to form a * new String.

diff --git a/src/test/java/org/apache/commons/lang3/StringUtilCenterTest.java b/src/test/java/org/apache/commons/lang3/StringUtilCenterTest.java new file mode 100644 index 00000000000..308d0719a18 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/StringUtilCenterTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import java.util.concurrent.TimeUnit; + +import static org.apache.commons.lang3.StringUtils.leftPad; +import static org.apache.commons.lang3.StringUtils.repeat; +import static org.apache.commons.lang3.StringUtils.rightPad; + +/** + * Test to show whether using BitSet for removeAll() methods is faster than using HashSet. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class StringUtilCenterTest { + + @Benchmark + public void test0Old() { + centerOld("a", 20, 'a'); + } + + @Benchmark + public void test0New() { + centerNew("a", 20, 'a'); + } + + @Benchmark + public void test1Old() { + centerOld("a", 10000000, ' '); + } + + @Benchmark + public void test1New() { + centerNew("a", 10000000, ' '); + } + + /** + *

Centers a String in a larger String of size {@code size}. + * Uses a supplied character as the value to pad the String with.

+ * + *

If the size is less than the String length, the String is returned. + * A {@code null} String returns {@code null}. + * A negative size is treated as zero.

+ * + *
+     * StringUtils.center(null, *, *)     = null
+     * StringUtils.center("", 4, ' ')     = "    "
+     * StringUtils.center("ab", -1, ' ')  = "ab"
+     * StringUtils.center("ab", 4, ' ')   = " ab "
+     * StringUtils.center("abcd", 2, ' ') = "abcd"
+     * StringUtils.center("a", 4, ' ')    = " a  "
+     * StringUtils.center("a", 4, 'y')    = "yayy"
+     * 
+ * + * @param str the String to center, may be null + * @param size the int size of new String, negative treated as zero + * @param padChar the character to pad the new String with + * @return centered String, {@code null} if null String input + * @since 2.0 + */ + public static String centerNew(String str, final int size, final char padChar) { + if (str == null || size <= 0) { + return str; + } + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; + } + StringBuilder stringBuilder = new StringBuilder(size); + repeat(stringBuilder, padChar, pads / 2); + stringBuilder.append(str); + repeat(stringBuilder, padChar, size - (strLen + pads / 2)); + return stringBuilder.toString(); + } + + /** + *

Centers a String in a larger String of size {@code size}. + * Uses a supplied character as the value to pad the String with.

+ * + *

If the size is less than the String length, the String is returned. + * A {@code null} String returns {@code null}. + * A negative size is treated as zero.

+ * + *
+     * StringUtils.center(null, *, *)     = null
+     * StringUtils.center("", 4, ' ')     = "    "
+     * StringUtils.center("ab", -1, ' ')  = "ab"
+     * StringUtils.center("ab", 4, ' ')   = " ab "
+     * StringUtils.center("abcd", 2, ' ') = "abcd"
+     * StringUtils.center("a", 4, ' ')    = " a  "
+     * StringUtils.center("a", 4, 'y')    = "yayy"
+     * 
+ * + * @param str the String to center, may be null + * @param size the int size of new String, negative treated as zero + * @param padChar the character to pad the new String with + * @return centered String, {@code null} if null String input + * @since 2.0 + */ + public static String centerOld(String str, final int size, final char padChar) { + if (str == null || size <= 0) { + return str; + } + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; + } + str = leftPad(str, strLen + pads / 2, padChar); + str = rightPad(str, size, padChar); + return str; + } +}