在Java中,String类是immutable(不可变的):任何修改操作都会创建一个新对象。StringBuilder和StringBuffer类是可变的,用于循环内的连接和复杂转换。
关键区别:
String:不可变,线程安全,无需额外同步。适合可读的、不变的文本(例如,密钥、消息)。StringBuilder:可变,不线程安全,但连接速度快。用于字符串多次变化的场景。StringBuffer:可变,线程安全(方法已同步),但在性能上不如StringBuilder。速度比较示例:
String s = ""; for (int i = 0; i < 10000; i++) { s += i; // 每次都会创建新的String,很慢! } // 更好的方式: StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append(i); } String result = sb.toString();
潜在问题:
String.intern()可能在有大量唯一字符串时引发OutOfMemoryError,尤其在PermGen/Metaspace中。问题: "在循环内使用"+"操作符连接字符串是否有效?"
回答: 不,每次都会创建新的String对象,这会大量占用内存并负担GC。对于许多操作,最好使用StringBuilder或StringBuffer(如果需要线程安全)。
示例:
String s = ""; for (int i = 0; i < 1000; i++) { s += i; // 非常低效! } // vs StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(i); }
故事
在一个银行项目中,用"+"运算符在大循环中连接字符串使得夜间分析速度降低了15倍。通过替换为StringBuilder解决了这个问题,执行时间从40分钟缩短到2分钟。
故事
一位年轻开发人员对线程使用不当,在同一个外观对象中使用StringBuilder,该对象被多个线程同时访问。这导致了随机的错误和不正确的结果,因为缺乏同步。
故事
在一个项目中,通过String.intern()创建唯一标签。当用户数量达到数千万时,JVM抛出了OutOfMemoryError: PermGen space。通过放弃使用intern()并转向其他缓存机制解决了问题。