浏览代码

fix StrBuilder bug

Looly 6 年之前
父节点
当前提交
4f811fc984

+ 2 - 0
CHANGELOG.md

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

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java

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

+ 89 - 65
hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java

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

+ 31 - 0
hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java

@@ -86,4 +86,35 @@ public class StrBuilderTest {
 		builder.append(123).append(456.123D).append(true).append('\n');
 		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());
+	}
 }