fix StrBuilder bug

This commit is contained in:
Looly
2019-09-27 19:35:39 +08:00
parent 60f3970b04
commit 4f811fc984
4 changed files with 123 additions and 66 deletions

View File

@@ -13,6 +13,8 @@
* 【extra】 修复Mail中sslEnable无效问题pr#74@Gitee * 【extra】 修复Mail中sslEnable无效问题pr#74@Gitee
* 【extra】 修复CsvParser中最后一行双引号没有去除的问题pr#73@Gitee * 【extra】 修复CsvParser中最后一行双引号没有去除的问题pr#73@Gitee
* 【crypto】 修复SM2算法在自定义密钥时无效问题issue#I12P5I@Gitee * 【crypto】 修复SM2算法在自定义密钥时无效问题issue#I12P5I@Gitee
* 【core】 修复StopWatch.prettyPrint条件问题issue#I12RAC@Gitee
* 【core】 修复StrBuilder.del无法删除最后一个字符的问题issue#I12R14@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@@ -312,7 +312,7 @@ public class StopWatch {
public String prettyPrint() { public String prettyPrint() {
StringBuilder sb = new StringBuilder(shortSummary()); StringBuilder sb = new StringBuilder(shortSummary());
sb.append(FileUtil.getLineSeparator()); sb.append(FileUtil.getLineSeparator());
if (null != this.taskList) { if (null == this.taskList) {
sb.append("No task info kept"); sb.append("No task info kept");
} else { } else {
sb.append("---------------------------------------------").append(FileUtil.getLineSeparator()); sb.append("---------------------------------------------").append(FileUtil.getLineSeparator());

View File

@@ -1,12 +1,12 @@
package cn.hutool.core.text; package cn.hutool.core.text;
import java.io.Serializable;
import java.util.Arrays;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.io.Serializable;
import java.util.Arrays;
/** /**
* 可复用的字符串生成器,非线程安全 * 可复用的字符串生成器,非线程安全
* *
@@ -16,33 +16,42 @@ import cn.hutool.core.util.StrUtil;
public class StrBuilder implements CharSequence, Appendable, Serializable { public class StrBuilder implements CharSequence, Appendable, Serializable {
private static final long serialVersionUID = 6341229705927508451L; private static final long serialVersionUID = 6341229705927508451L;
/** 默认容量 */ /**
* 默认容量
*/
public static final int DEFAULT_CAPACITY = 16; public static final int DEFAULT_CAPACITY = 16;
/** 存放的字符数组 */ /**
* 存放的字符数组
*/
private char[] value; private char[] value;
/** 当前指针位置,或者叫做已经加入的字符数,此位置总在最后一个字符之后 */ /**
* 当前指针位置,或者叫做已经加入的字符数,此位置总在最后一个字符之后
*/
private int position; private int position;
/** /**
* 创建字符串构建器 * 创建字符串构建器
*
* @return {@link StrBuilder} * @return {@link StrBuilder}
*/ */
public static StrBuilder create() { public static StrBuilder create() {
return new StrBuilder(); return new StrBuilder();
} }
/** /**
* 创建字符串构建器 * 创建字符串构建器
*
* @param initialCapacity 初始容量 * @param initialCapacity 初始容量
* @return {@link StrBuilder} * @return {@link StrBuilder}
*/ */
public static StrBuilder create(int initialCapacity) { public static StrBuilder create(int initialCapacity) {
return new StrBuilder(initialCapacity); return new StrBuilder(initialCapacity);
} }
/** /**
* 创建字符串构建器 * 创建字符串构建器
*
* @param strs 初始字符串 * @param strs 初始字符串
* @return {@link StrBuilder} * @return {@link StrBuilder}
* @since 4.0.1 * @since 4.0.1
@@ -52,6 +61,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
} }
// ------------------------------------------------------------------------------------ Constructor start // ------------------------------------------------------------------------------------ Constructor start
/** /**
* 构造 * 构造
*/ */
@@ -67,7 +77,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
public StrBuilder(int initialCapacity) { public StrBuilder(int initialCapacity) {
value = new char[initialCapacity]; value = new char[initialCapacity];
} }
/** /**
* 构造 * 构造
* *
@@ -76,16 +86,17 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
*/ */
public StrBuilder(CharSequence... strs) { public StrBuilder(CharSequence... strs) {
this(ArrayUtil.isEmpty(strs) ? DEFAULT_CAPACITY : (totalLength(strs) + DEFAULT_CAPACITY)); this(ArrayUtil.isEmpty(strs) ? DEFAULT_CAPACITY : (totalLength(strs) + DEFAULT_CAPACITY));
for(int i = 0; i < strs.length; i++) { for (int i = 0; i < strs.length; i++) {
append(strs[i]); append(strs[i]);
} }
} }
// ------------------------------------------------------------------------------------ Constructor end // ------------------------------------------------------------------------------------ Constructor end
// ------------------------------------------------------------------------------------ Append // ------------------------------------------------------------------------------------ Append
/** /**
* 追加对象,对象会被转换为字符串 * 追加对象,对象会被转换为字符串
* *
* @param obj 对象 * @param obj 对象
* @return this * @return this
*/ */
@@ -106,7 +117,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 追加一个字符数组 * 追加一个字符数组
* *
* @param src 字符数组 * @param src 字符数组
* @return this * @return this
*/ */
@@ -119,8 +130,8 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 追加一个字符数组 * 追加一个字符数组
* *
* @param src 字符数组 * @param src 字符数组
* @param srcPos 开始位置(包括) * @param srcPos 开始位置(包括)
* @param length 长度 * @param length 长度
* @return this * @return this
@@ -140,9 +151,10 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
} }
// ------------------------------------------------------------------------------------ Insert // ------------------------------------------------------------------------------------ Insert
/** /**
* 追加对象,对象会被转换为字符串 * 追加对象,对象会被转换为字符串
* *
* @param obj 对象 * @param obj 对象
* @return this * @return this
*/ */
@@ -155,9 +167,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 插入指定字符 * 插入指定字符
* *
* @param index 位置 * @param index 位置
* @param c 字符 * @param c 字符
* @return this * @return this
*/ */
public StrBuilder insert(int index, char c) { public StrBuilder insert(int index, char c) {
@@ -171,9 +183,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
* 指定位置插入数据<br> * 指定位置插入数据<br>
* 如果插入位置为当前位置,则定义为追加<br> * 如果插入位置为当前位置,则定义为追加<br>
* 如果插入位置大于当前位置,则中间部分补充空格 * 如果插入位置大于当前位置,则中间部分补充空格
* *
* @param index 插入位置 * @param index 插入位置
* @param src 源数组 * @param src 源数组
* @return this * @return this
*/ */
public StrBuilder insert(int index, char[] src) { public StrBuilder insert(int index, char[] src) {
@@ -187,9 +199,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
* 指定位置插入数据<br> * 指定位置插入数据<br>
* 如果插入位置为当前位置,则定义为追加<br> * 如果插入位置为当前位置,则定义为追加<br>
* 如果插入位置大于当前位置,则中间部分补充空格 * 如果插入位置大于当前位置,则中间部分补充空格
* *
* @param index 插入位置 * @param index 插入位置
* @param src 源数组 * @param src 源数组
* @param srcPos 位置 * @param srcPos 位置
* @param length 长度 * @param length 长度
* @return this * @return this
@@ -219,9 +231,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
* 指定位置插入字符串的某个部分<br> * 指定位置插入字符串的某个部分<br>
* 如果插入位置为当前位置,则定义为追加<br> * 如果插入位置为当前位置,则定义为追加<br>
* 如果插入位置大于当前位置,则中间部分补充空格 * 如果插入位置大于当前位置,则中间部分补充空格
* *
* @param index 位置 * @param index 位置
* @param csq 字符串 * @param csq 字符串
* @return this * @return this
*/ */
public StrBuilder insert(int index, CharSequence csq) { public StrBuilder insert(int index, CharSequence csq) {
@@ -251,11 +263,11 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
* 指定位置插入字符串的某个部分<br> * 指定位置插入字符串的某个部分<br>
* 如果插入位置为当前位置,则定义为追加<br> * 如果插入位置为当前位置,则定义为追加<br>
* 如果插入位置大于当前位置,则中间部分补充空格 * 如果插入位置大于当前位置,则中间部分补充空格
* *
* @param index 位置 * @param index 位置
* @param csq 字符串 * @param csq 字符串
* @param start 字符串开始位置(包括) * @param start 字符串开始位置(包括)
* @param end 字符串结束位置(不包括) * @param end 字符串结束位置(不包括)
* @return this * @return this
*/ */
public StrBuilder insert(int index, CharSequence csq, int start, int end) { public StrBuilder insert(int index, CharSequence csq, int start, int end) {
@@ -289,12 +301,13 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
} }
// ------------------------------------------------------------------------------------ Others // ------------------------------------------------------------------------------------ Others
/** /**
* 将指定段的字符列表写出到目标字符数组中 * 将指定段的字符列表写出到目标字符数组中
* *
* @param srcBegin 起始位置(包括) * @param srcBegin 起始位置(包括)
* @param srcEnd 结束位置(不包括) * @param srcEnd 结束位置(不包括)
* @param dst 目标数组 * @param dst 目标数组
* @param dstBegin 目标起始位置(包括) * @param dstBegin 目标起始位置(包括)
* @return this * @return this
*/ */
@@ -316,7 +329,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 是否有内容 * 是否有内容
* *
* @return 是否有内容 * @return 是否有内容
*/ */
public boolean hasContent() { public boolean hasContent() {
@@ -325,16 +338,16 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 是否为空 * 是否为空
* *
* @return 是否为空 * @return 是否为空
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return position == 0; return position == 0;
} }
/** /**
* 删除全部字符,位置归零 * 删除全部字符,位置归零
* *
* @return this * @return this
*/ */
public StrBuilder clear() { public StrBuilder clear() {
@@ -343,7 +356,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 删除全部字符,位置归零 * 删除全部字符,位置归零
* *
* @return this * @return this
*/ */
public StrBuilder reset() { public StrBuilder reset() {
@@ -354,51 +367,61 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 删除到指定位置<br> * 删除到指定位置<br>
* 如果新位置小于等于0则删除全部 * 如果新位置小于等于0则删除全部
* *
* @param newPosition 新的位置,不包括这个位置 * @param newPosition 新的位置,不包括这个位置
* @return this * @return this
*/ */
public StrBuilder delTo(int newPosition) { public StrBuilder delTo(int newPosition) {
if (newPosition < 0) { if (newPosition < 0) {
this.reset(); newPosition = 0;
} else if (newPosition < this.position) {
this.position = newPosition;
} }
return this; return del(newPosition, this.position);
} }
/** /**
* 删除指定长度的字符 * 删除指定长度的字符,规则如下:
* *
* @param start 开始位置(包括) * <pre>
* @param end 结束位置(不包括 * 1、end大于等于最大长度结束按照最大长度计算相当于删除start之后虽有部分性能最好
* 2、end小于start时抛出StringIndexOutOfBoundsException
* 3、start小于0 按照0处理
* 4、start等于end不处理
* 5、start和end都位于长度区间内删除这段内容内存拷贝
* </pre>
*
* @param start 开始位置负数按照0处理包括
* @param end 结束位置,超出最大长度按照最大长度处理(不包括)
* @return this * @return this
* @throws StringIndexOutOfBoundsException 当start > end抛出此异常
*/ */
public StrBuilder del(int start, int end) { public StrBuilder del(int start, int end) throws StringIndexOutOfBoundsException {
if (start < 0) { if (start < 0) {
start = 0; start = 0;
} }
if (end > this.position) {
end = this.position; if (end >= this.position) {
} // end在边界及以外相当于删除后半部分
if (start > end) {
throw new StringIndexOutOfBoundsException("Start is greater than End.");
}
if (end == this.position) {
this.position = start; this.position = start;
return this;
} else if (end < 0) {
// start和end都为0的情况下表示删除全部
end = 0;
} }
int len = end - start; int len = end - start;
// 截取中间部分,需要将后半部分复制到删除的开始位置
if (len > 0) { if (len > 0) {
System.arraycopy(value, start + len, value, start, this.position - end); System.arraycopy(value, start + len, value, start, this.position - end);
this.position -= len; this.position -= len;
} else if (len < 0) {
throw new StringIndexOutOfBoundsException("Start is greater than End.");
} }
return this; return this;
} }
/** /**
* 生成字符串 * 生成字符串
* *
* @param isReset 是否重置,重置后相当于空的构建器 * @param isReset 是否重置,重置后相当于空的构建器
* @return 生成的字符串 * @return 生成的字符串
*/ */
@@ -415,7 +438,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 重置并返回生成的字符串 * 重置并返回生成的字符串
* *
* @return 字符串 * @return 字符串
*/ */
public String toStringAndReset() { public String toStringAndReset() {
@@ -450,7 +473,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 返回自定段的字符串 * 返回自定段的字符串
* *
* @param start 开始位置(包括) * @param start 开始位置(包括)
* @return this * @return this
*/ */
@@ -460,9 +483,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 返回自定段的字符串 * 返回自定段的字符串
* *
* @param start 开始位置(包括) * @param start 开始位置(包括)
* @param end 结束位置(不包括) * @param end 结束位置(不包括)
* @return this * @return this
*/ */
public String subString(int start, int end) { public String subString(int start, int end) {
@@ -470,10 +493,11 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
} }
// ------------------------------------------------------------------------------------ Private method start // ------------------------------------------------------------------------------------ Private method start
/** /**
* 指定位置之后的数据后移指定长度 * 指定位置之后的数据后移指定长度
* *
* @param index 位置 * @param index 位置
* @param length 位移长度 * @param length 位移长度
*/ */
private void moveDataAfterIndex(int index, int length) { private void moveDataAfterIndex(int index, int length) {
@@ -490,7 +514,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 确认容量是否够用,不够用则扩展容量 * 确认容量是否够用,不够用则扩展容量
* *
* @param minimumCapacity 最小容量 * @param minimumCapacity 最小容量
*/ */
private void ensureCapacity(int minimumCapacity) { private void ensureCapacity(int minimumCapacity) {
@@ -502,7 +526,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
/** /**
* 扩展容量<br> * 扩展容量<br>
* 首先对容量进行二倍扩展,如果小于最小容量,则扩展为最小容量 * 首先对容量进行二倍扩展,如果小于最小容量,则扩展为最小容量
* *
* @param minimumCapacity 需要扩展的最小容量 * @param minimumCapacity 需要扩展的最小容量
*/ */
private void expandCapacity(int minimumCapacity) { private void expandCapacity(int minimumCapacity) {
@@ -519,18 +543,18 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
} }
value = Arrays.copyOf(value, newCapacity); value = Arrays.copyOf(value, newCapacity);
} }
/** /**
* 给定字符串数组的总长度<br> * 给定字符串数组的总长度<br>
* null字符长度定义为0 * null字符长度定义为0
* *
* @param strs 字符串数组 * @param strs 字符串数组
* @return 总长度 * @return 总长度
* @since 4.0.1 * @since 4.0.1
*/ */
private static int totalLength(CharSequence... strs) { private static int totalLength(CharSequence... strs) {
int totalLength = 0; int totalLength = 0;
for(int i = 0 ; i < strs.length; i++) { for (int i = 0; i < strs.length; i++) {
totalLength += (null == strs[i] ? 4 : strs[i].length()); totalLength += (null == strs[i] ? 4 : strs[i].length());
} }
return totalLength; return totalLength;

View File

@@ -86,4 +86,35 @@ public class StrBuilderTest {
builder.append(123).append(456.123D).append(true).append('\n'); builder.append(123).append(456.123D).append(true).append('\n');
Assert.assertEquals("123456.123true\n", builder.toString()); Assert.assertEquals("123456.123true\n", builder.toString());
} }
@Test
public void delTest() {
// 删除全部测试
StrBuilder strBuilder = new StrBuilder("ABCDEFG");
int length = strBuilder.length();
StrBuilder builder = strBuilder.del(0, length);
Assert.assertEquals("", builder.toString());
}
@Test
public void delTest2() {
// 删除中间部分测试
StrBuilder strBuilder = new StrBuilder("ABCDEFG");
int length = strBuilder.length();
StrBuilder builder = strBuilder.del(2,6);
Assert.assertEquals("ABG", builder.toString());
}
@Test
public void delToTest() {
StrBuilder strBuilder = new StrBuilder("ABCDEFG");
// 不处理
StrBuilder builder = strBuilder.delTo(7);
Assert.assertEquals("ABCDEFG", builder.toString());
// 删除全部
builder = strBuilder.delTo(0);
Assert.assertEquals("", builder.toString());
}
} }