String SubString 的问题

本文介绍了一个关于String类substring方法导致的Java内存泄漏问题,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我的RSSNEWS的程序中,抛出

java.sql.BatchUpdateException: ORA-12899: value too large for column "RSSNEWS"."NEWS"."DES" (actual: 2002, maximum: 2000)

 

而在代码中有我有设置DES字段的长度检查,代码如下:

String des =  entry.getDescription().getValue();
if(des.length() > 2000)
	  des = des.substring(0, 2000); 	   
news.setDes(temp);

 
为什么还会抛出上面的异常呢

 

答案在网上找到了:

http://www.blogjava.net/jnbzwm/archive/2010/09/01/330559.html

 

String类substring方法导致的Java内存泄漏问题

此问题在项目中被发现,经查看JDK源码(JDK1.6),String类的public String substring(int beginIndex, int endIndex)的实现让我很意外。

想重现这个场景很容易,请看代码。

 1 import  java.util.ArrayList;
 2 import  java.util.List;
 3
 4 public   class  LeakTest  {
 5    public static void main(Stringargs) {
 6        List<String> handler = new ArrayList<String>();
 7        for(int i = 0; i < 100000; i++{
 8            Huge h = new Huge();
 9            handler.add(h.getSubString(15));
10        }

11    }

12}

13
14 class  Huge  {
15    private String str = new String(new char[100000]);
16    public String getSubString(int begin, int end) {
17        return str.substring(begin, end);
18    }

19}

执行此代码结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

 

问题就出在Huge类的 getSubString 方法,它调用了String类的substring方法。

来让我们看看 substring 类的实现吧,JDK源码如下:

 1      public  String substring( int  beginIndex,  int  endIndex)  {
 2    if (beginIndex < 0{
 3        throw new StringIndexOutOfBoundsException(beginIndex);
 4    }

 5    if (endIndex > count) {
 6        throw new StringIndexOutOfBoundsException(endIndex);
 7    }

 8    if (beginIndex > endIndex) {
 9        throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
10    }

11    return ((beginIndex == 0&& (endIndex == count)) ? this :
12        new String(offset + beginIndex, endIndex - beginIndex, value);
13    }

再让我们接下来看看 new String(offset + beginIndex, endIndex - beginIndex, value); 的实现:


1      //  Package private constructor which shares value array for speed.
2     String( int  offset,  int  count,  char  value[])  {
3    this.value = value;
4    this.offset = offset;
5    this.count = count;
6    }


char[] value 数组被共享了。

 

在我们的main函数里的循环中,每循环一次后,我们希望Huge对象被回收,且释放它占有的内存。

但实际上 private String str = new String(new char[100000]); 占有的内存并不会被释放。

因为 我们通过 Huge 类的 getSubString 方法得到的 String 对象还存在(存在于handler的列表中),

它虽然是 length 只有 4 的对象,却享有着 char[100000] 的空间。

 

解决方案:

可以修改Huge 类的 getSubString 方法如下:

1      public  String getSubString( int  begin,  int  end)  {
2        return new String(str.substring(begin, end));
3    }

只要再套一个String的构造方法即可。

### Java 中 `String` 类的 `substring()` 方法使用教程 #### 方法概述 `substring()` 是 Java 中 `String` 类的一个重要方法,用于获取字符串的一部分作为新的字符串。该方法有两种重载形式: - **单参数版本**:从指定索引开始至字符串结尾创建子字符串。 ```java public String substring(int beginIndex) ``` - **双参数版本**:从指定起始索引来截止于结束索引之前的位置创建子字符串。 ```java public String substring(int beginIndex, int endIndex) ``` 这两种形式都遵循一个原则——原始字符串不会被修改,因为 Java 中的字符串对象是不可变的[^1]。 #### 单参数版实例 当只提供一个参数时,表示从给定索引位置一直到整个字符串末端生成一个新的子串。 ```java public class SingleParamSubstring { public static void main(String[] args) { String originalStr = "Hello, Java!"; // 从索引7开始截取直至最后 String subStr = originalStr.substring(7); System.out.println(subStr); // 输出: Java! } } ``` #### 双参数版实例 对于两个参数的情况,第一个参数代表子串起点(包含),第二个参数则是终点(不包含)。 ```java public class DoubleParamsSubstring { public static void main(String[] args) { String sourceStr = "abcdefg"; // 从索引2开始到索引5前停止 String partOne = sourceStr.substring(2); String partTwo = sourceStr.substring(2, 5); System.out.println(partOne); // 输出: cdefg System.out.println(partTwo); // 输出: cde } } ``` 需要注意的是,在调用带有两个参数的形式时,确保 `beginIndex` 小于等于 `endIndex` 并且两者都在合法范围内;否则会抛出异常[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值