JavaSE-05-字符串(全面深入)
JavaSE-05-字符串(全面深入)
字符串在各个编程语言中都是使用非常多!文本处理,基本都是最终落到字符串上去替换、拼接、截取、统计等操作。String是一个重要强大的类。
Java中,String类型容易认为是基础类型,用得很顺手,其实它是引用类型,被final修饰,体验官方对其的保护,不允许子类继承破坏,底层是final byte[] value不变的字节数组维护,所以初始化了,其值就不变;同时学习StringBuilder、StringBuffer等可变的字符串容器,以及format、MessageFormat字符串格式化,最后一些字符串常见使用场景优化等,全面深入了解字符串。
一、String类(不变)
Java 中出现的所有字符串文字,如“water”,都被实现为String类的实例。换言之,Java 程序中所有的双引号字符串,都是 String 类的对象。其UML类图如下:
基本特点
- 字符串不可变,创建后其值不能被改变
- 虽然 String 的值是不可变的,但是它们可以利用字符串常量池进行共享
- 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )
public final class String implements java .io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc { /** * The value is used for character storage. * * @implNote This field is trusted by the VM, and is a subject to * constant folding if String instance is constant. Overwriting this * field after construction will cause problems. * * Additionally, it is marked with { @link Stable} to trust the contents * of the array. No other facility in JDK provides this functionality (yet). * { @link Stable} is safe here, because value is never null. */ @Stable private final byte [] value; // 其他 }
构造方法
| 方法名 | 说明 |
|---|---|
| public String() | 创建一个空白字符串对象,不含有任何内容 |
| public String(char[] chs) | 根据字符数组的内容,来创建字符串对象 |
| public String(byte[] bys) | 根据字节数组的内容,来创建字符串对象 |
| String s = “abc”; | 直接赋值的方式创建字符串对象,内容就是abc |
- 示例代码
public class StringDemo01 { public static void main (String[] args) { //public String():创建一个空白字符串对象,不含有任何内容 String s1 = new String (); System.out.println( "s1:" + s1); //public String(char[] chs):根据字符数组的内容,来创建字符串对象 char [] chs = { 'a' , 'b' , 'c' }; String s2 = new String (chs); System.out.println( "s2:" + s2); //public String(byte[] bys):根据字节数组的内容,来创建字符串对象 byte [] bys = { 97 , 98 , 99 }; String s3 = new String (bys); System.out.println( "s3:" + s3); //String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc String s4 = "abc" ; System.out.println( "s4:" + s4); } }
创建字符串对象两种方式的区别
- 通过构造方法创建 通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同
- 直接赋值方式创建 以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串常量池中维护。
推荐使用直接赋值的方式创建字符串,利用字面量可复用的特点,节约资源,提高性能,避免new对象。
多行文本(字符串模板)
JDK13+出现,好处是轻松保留字符串的样式,如HTML,所见即所得。
Html模板:
// 多行文本支持(JDK 13+) public void multiLineString () { String html = """ <html> <body> <h1>Hello</h1> </body> </html> """ ; System.out.println(html); }
json报文示例:
包括注释,破坏了Json的语法,所以无法转换为实体,仅作为参考示例。
static String requestDemoWithDescAndCanNotBeJsonParsed = """ { "merchantCode": "898340149000005", // 商户号 "terminalCode": "00000001", // 终端号 "transactionAmount": "1", // 交易金额 单位:分 "transactionCurrencyCode": "156", // 交易币种 "merchantOrderId": "SO16497473287935135489683", // 商户订单号 "merchantRemark": "003598测试-雁塔门店", // 商户备注 "payMode": "CODE_SCAN", // 支付方式 "payCode": "134524350966727175", // 支付码 "deviceType": "02", // 设备类型 "systemTraceNum": "123456", // 系统跟踪号 "goods": [ { "goodsId": "001", // 商品ID "goodsName": "鸡蛋", // 商品名称 "quantity": "10", // 数量 "price": "1", // 价格 "goodsCategory": "food meterial", // 商品分类 "body": "two eggs", // 商品描述 "discount": "" // 折扣 } ], "srcReserved": "", // 源保留域 "storeId": "01", // 门店号 "limitCreditCard": "false", // 是否限制信用卡 "operatorId": "01", // 操作员ID "bizIdentifier": "", // 业务标识 "goodsTag": "", // 商品标签 "installmentFlag": "true", // 分期标识 "installmentNumber": "12", // 分期期数 "retCommParams": { "foodOrderType": "pre_order", // 预订单类型 "eduSchoolId": "01", // 学校ID "eduScene": "", // 教育场景 "parkId": "", // 停车场ID "vehicleNo": "" // 车牌号 }, "transChnl": "", // 交易渠道 "thirdPartyInstalSubsFlag": "", // 第三方分期补贴标识 "feeRatio": "", // 费率比例 "costSubsidy": "", // 成本补贴 "subAppId": "", // 子应用ID "serialNum": "", // 序列号 "encryptRandNum": "", // 加密随机数 "secretText": "", // 密文 "appVersion": "", // 应用版本 "longitude": "-121.48352", // 经度 "latitude": "+31.221345", // 纬度 "networkLicense": "P3100", // 网络许可证 "ip": "172.20.11.089", // IP地址 "name": "张*三", // 姓名 "mobile": "131****3453", // 手机号 "certType": "IDENTITY_CARD", // 证件类型 "certNo": "110101********9008", // 证件号码 "fixBuyer": "false", // 固定买家 "targetChnl": "", // 目标渠道 "invocationMode": "", // 调用模式 "orderDesc": "", // 订单描述 "pwdEnc": "", // 密码加密 "pwdTransKeyEnc": "", // 密码传输密钥加密 "creditFeeRatio": "", // 信用费率比例 "acctAmt": "", // 账户金额 "location": "BD09", // 位置 "discountCode": "", // 折扣码 "promoParams": "", // 促销参数 "presetPayTool": {}, // 预设支付工具 "transparentFields": {}, // 透明字段 "encryptData": "" // 加密数据 } """ ;
两种字符串比较方式
==号的作用
- 比较基本数据类型:比较的是具体的值,如:12==13,false
- 比较引用数据类型:比较的是对象地址值,如:0x001 == 0x003,false
equals方法的作用
public boolean equals (String s) 比较两个字符串内容是否相同、区分大小写
示例代码
public class StringDemo02 { public static void main (String[] args) { //构造方法的方式得到对象 char [] chs = { 'a' , 'b' , 'c' }; String s1 = new String (chs); String s2 = new String (chs); //直接赋值的方式得到对象 String s3 = "abc" ; String s4 = "abc" ; //比较字符串对象地址是否相同 System.out.println(s1 == s2); // false System.out.println(s1 == s3); // false System.out.println(s3 == s4); // true,常量池共用字符串,值一样 System.out.println( "--------" ); //比较字符串内容是否相同 System.out.println(s1.equals(s2)); // true,equals方法被重写,比较的是内容 System.out.println(s1.equals(s3)); // 同上 System.out.println(s3.equals(s4)); // 同上 } }
小技巧:
使用"aa".equals(xx),这种字符串在前的比较方式,避免xx空指针null。
以下是 String 类中一些常用方法的举例说明,结合代码示例和应用场景:
substring截取子串
方法:substring(int beginIndex, int endIndex)
作用: 截取字符串的一部分。
String str = "Hello World" ; String subStr = str.substring( 0 , 5 ); // 输出: Hello
应用场景:
- 提取固定格式字符串的部分内容(如日志解析、文件名提取)。
- 字符串截断处理。
split分割
方法:split(String regex)
作用: 使用正则表达式分割字符串为数组。
String str = "apple,banana,cherry" ; String[] parts = str.split( "," ); // 输出: ["apple", "banana", "cherry"]
应用场景:
- 解析 CSV 数据。
- URL 参数拆分。
- 日志信息解析。
replace替换某部分
方法:replace(CharSequence target, CharSequence replacement)
作用: 替换字符串中的某部分。
String str = "Hello World" ; String newStr = str.replace( "World" , "Java" ); // 输出: Hello Java
应用场景:
- 动态替换模板字符串。
- 数据清洗(如替换敏感词)。
contains包含判断
方法:contains(CharSequence s)
作用: 判断字符串是否包含指定子串。
String str = "Hello World" ; boolean contains = str.contains( "World" ); // 输出: true
应用场景:
- 检查用户输入是否包含关键词。
- 过滤非法字符或敏感词。
第一次字符出现的索引
方法:indexOf(String str)
作用: 返回指定子串在字符串中第一次出现的索引。
String str = "Hello World" ; int index = str.indexOf( "World" ); // 输出: 6
应用场景:
- 定位特定内容的位置。
- 辅助实现自定义字符串解析逻辑。
去除两端空白符
方法:trim()
作用: 去除字符串两端的空白字符。
String str = " Hello World " ; String trimmed = str.trim(); // 输出: Hello World
应用场景:
- 用户输入清理(如登录名、密码)。
- 数据预处理(如读取配置文件)。
大小写转换
方法:toLowerCase() / toUpperCase()
作用: 将字符串转换为小写或大写形式。
String str = "Hello World" ; String lower = str.toLowerCase(); // 输出: hello world String upper = str.toUpperCase(); // 输出: HELLO WORLD
应用场景:
- 不区分大小写的比较。
- 格式化输出(如用户名显示统一格式)。
获取长度
方法:length()
作用: 获取字符串的长度。
String str = "Hello" ; int len = str.length(); // 输出: 5
应用场景:
- 验证用户输入长度限制。
- 控制文本显示区域。
获取字符
方法:charAt(int index)
作用: 获取指定索引位置的字符。
String str = "Hello" ; char ch = str.charAt( 1 ); // 输出: e
应用场景:
- 自定义字符处理逻辑。
- 实现加密/解密算法。
equals比较
方法:equals(Object anObject) / equalsIgnoreCase(String anotherString)
作用: 比较两个字符串是否相等,equalsIgnoreCase 忽略大小写。
String str1 = "Hello" ; String str2 = "hello" ; boolean equals = str1.equals(str2); // 输出: false boolean ignoreCase = str1.equalsIgnoreCase(str2); // 输出: true
应用场景:
- 登录验证(忽略大小写的用户名匹配)。
- 文件扩展名检查(如
.jpg,.JPG)。
前后缀检查
方法:startsWith(String prefix) / endsWith(String suffix)
作用: 检查字符串是否以指定前缀或后缀开头/结尾。
String str = "http://example.com" ; boolean starts = str.startsWith( "http" ); // 输出: true boolean ends = str.endsWith( ".com" ); // 输出: true
应用场景:
- URL 或文件路径校验。
- 格式校验(如邮箱地址、电话号码)。
获取常量池引用
方法:intern()
作用: 返回字符串在常量池中的引用,确保相同内容的字符串共享内存。
String str1 = new String ( "hello" ); String str2 = str1.intern(); String str3 = "hello" ; System.out.println(str2 == str3); // 输出: true
应用场景:
- 减少重复字符串对象(适用于大量重复字符串场景)。
- 优化内存使用(如大数据分析中字符串去重)。
正则匹配
方法:matches(String regex)
作用: 判断字符串是否匹配某个正则表达式。
String email = "test@example.com" ; boolean valid = email.matches( "\\w+@\\w+\\.\\w+" ); // 输出: true
应用场景:
- 输入校验(如邮箱、手机号、身份证号)。
- 数据清洗。
concat拼接
方法:concat(String str)
作用: 拼接两个字符串。
String str1 = "Hello" ; String str2 = "World" ; String result = str1.concat(str2); // 输出: HelloWorld
应用场景:
- 简单拼接操作(注意性能问题,高频拼接推荐使用
StringBuilder)。
转字符数组
方法:toCharArray()
作用: 将字符串转换为字符数组。
String str = "Hello" ; char [] chars = str.toCharArray(); // 输出: ['H', 'e', 'l', 'l', 'o']
应用场景:
- 字符串加密/解密。
- 自定义字符处理逻辑。
常用方法总结
| 方法 | 应用场景 |
|---|---|
| substring | 提取子串 |
| split | 分割字符串 |
| replace | 替换内容 |
| contains | 包含判断 |
| indexOf | 查找位置 |
| trim | 去除空格 |
| toLowerCase / toUpperCase | 大小写转换 |
| length | 获取长度 |
| charAt | 获取字符 |
| equals / equalsIgnoreCase | 字符串比较 |
| startsWith / endsWith | 前缀/后缀判断 |
| intern | 常量池管理 |
| matches | 正则匹配 |
| concat | 字符串拼接 |
| toCharArray | 转换为字符数组 |
这些方法是日常开发中最常用的 String 方法,合理使用可以显著提升字符串处理效率。
二、StringBuilder类(可变容器)
StringBuilder 可以看成是一个容器,创建之后里面的内容是可变的。当我们在拼接字符串和反转字符串的时候会使用到。方法如下:
基本使用
包括创建、添加、反转、获取长度等
public class StringBuilderDemo3 { public static void main (String[] args) { //1.创建对象 StringBuilder sb = new StringBuilder ( "abc" ); //2.添加元素 /*sb.append(1); sb.append(2.3); sb.append(true);*/ //反转 sb.reverse(); //获取长度 int len = sb.length(); System.out.println(len); //因为StringBuilder是Java已经写好的类 //java在底层对他做了一些特殊处理。 //打印对象不是地址值而是属性值。 System.out.println(sb); } }
打印,本质是调用对象的toString方法,而StringBuilder的该方法,被重写,如下:
@Override @IntrinsicCandidate public String toString () { // Create a copy, don't share the array return new String ( this ); }
接着是创建了一个String对象,看出其存储字符的不变数组value被拷贝了asb的字节数组,就是复制了一波收集好的内容。打印的最终就是这个创建了复制了一样内容的String对象。
public String (StringBuilder builder) { this (builder, null ); } String(AbstractStringBuilder asb, Void sig) { byte [] val = asb.getValue(); int length = asb.length(); if (asb.isLatin1()) { this .coder = LATIN1; this .value = Arrays.copyOfRange(val, 0 , length); } else { // only try to compress val if some characters were deleted. if (COMPACT_STRINGS && asb.maybeLatin1) { byte [] buf = StringUTF16.compress(val, 0 , length); if (buf != null ) { this .coder = LATIN1; this .value = buf; return ; } } this .coder = UTF16; this .value = Arrays.copyOfRange(val, 0 , length << 1 ); } }
this链式编程
其成员方法append返回this代表当前的StringBuilder对象,优雅!
public class StringBuilderDemo4 { public static void main (String[] args) { //1.创建对象 StringBuilder sb = new StringBuilder (); //2.添加字符串 sb.append( "aaa" ).append( "bbb" ).append( "ccc" ).append( "ddd" ); System.out.println(sb); //aaabbbcccddd //3.再把StringBuilder变回字符串 String str = sb.toString(); System.out.println(str); //aaabbbcccddd } }
对称字符串
键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
对称字符串:123321、111 非对称字符串:123123
代码示例:
public class Test { public static void main (String[] args) { Scanner sc = new Scanner (System.in); System.out.println( "请输入一个字符串" ); String str = sc.next(); String result = new StringBuilder ().append(str).reverse().toString(); if (str.equals(result)){ System.out.println( "当前字符串是对称字符串" ); } else { System.out.println( "当前字符串不是对称字符串" ); } } }
拼接字符串更高性能
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回。调用该方法,并在控制台输出结果。例如:数组为int[] arr = {1,2,3}; 执行方法后的输出结果为:[1, 2, 3]。这种方式,比String的+拼接方式性能要高5-10倍。
代码示例:
public class Test { public static void main (String[] args) { //1.定义数组 int [] arr = { 1 , 2 , 3 }; //2.调用方法把数组变成字符串 String str = arrToString(arr); System.out.println(str); } public static String arrToString ( int [] arr) { StringBuilder sb = new StringBuilder (); sb.append( "[" ); for ( int i = 0 ; i < arr.length; i++) { if (i == arr.length - 1 ){ sb.append(arr[i]); } else { sb.append(arr[i]).append( ", " ); } } sb.append( "]" ); return sb.toString(); } }
线程安全处理
StringBuilder线程不安全,多线程拼接同一个StringBuilder对象时会有问题。解决的方案多样:
- 给这个对象资源修改时,添加锁,
synchronized方法,或代码块 - 使用
StringBuffer线程安全类,方法一样 - 使用
ThreadLocal线程本地变量,每个线程处理自己的
// 使用ThreadLocal保证线程安全 public class ThreadSafeStringProcessor { private static final ThreadLocal<StringBuilder> builders = ThreadLocal.withInitial(() -> new StringBuilder ( 1024 )); public static String formatData (String prefix, String suffix) { StringBuilder sb = builders.get(); sb.setLength( 0 ); return sb.append(prefix).append(suffix).toString(); } }
三、StringBuffer类(线程安全)
与StringBuilder类相比,方法加了Synchronized关键字,线程安全!方法使用和StringBuidler一样。
public StringBuffer (CharSequence seq) { super (seq); } @Override public synchronized int compareTo (StringBuffer another) { return super .compareTo(another); } @Override public synchronized int length () { // 线程安全 return count; } @Override public synchronized int capacity () { // 线程安全 return super .capacity(); }
四、StringJoiner类(连接器)
StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。作用:提高字符串拼接的操作效率,容易输出带有间隔符的字符串。
基本使用:
//1.创建一个对象,并指定中间的间隔符号 StringJoiner sj = new StringJoiner ( "---" ); //2.添加元素 sj.add( "aaa" ).add( "bbb" ).add( "ccc" ); //3.打印结果 System.out.println(sj); //aaa---bbb---ccc
//1.创建对象 StringJoiner sj = new StringJoiner ( ", " , "[" , "]" ); //2.添加元素 sj.add( "aaa" ).add( "bbb" ).add( "ccc" ); int len = sj.length(); System.out.println(len); //15 //3.打印 System.out.println(sj); //[aaa, bbb, ccc] String str = sj.toString(); System.out.println(str); //[aaa, bbb, ccc]
五、字符串内存分析
-
- 字符串存储的内存原理
String s = “abc”;直接赋值特点: 此时字符串abc是存在字符串常量池中的。 先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。所以,直接赋值的方式,代码简单,而且节约内存。
- 字符串存储的内存原理
-
- new出来的字符串看到new关键字,一定是在堆里面开辟了一个小空间。
String s1 = new String(“abc”);String s2 = “abc”;s1记录的是new出来的,在堆里面的地址值。s2是直接赋值的,所以记录的是字符串常量池中的地址值。
- new出来的字符串看到new关键字,一定是在堆里面开辟了一个小空间。
-
==号比较的到底是什么?如果比较的是基本数据类型:比的是具体的数值是否相等。如果比较的是引用数据类型:比的是地址值是否相等。结论:==只能用于比较基本数据类型。不能比较引用数据类型。
六、String.format格式化
String.format 是 Java 中用于格式化字符串的常用方法,它允许开发者按照指定的格式生成字符串。String.format 是一个功能强大且灵活的字符串格式化工具,适用于需要将变量嵌入字符串模板的场景。但在性能敏感或大规模循环中应谨慎使用,避免不必要的性能损耗。
String formattedString = String.format(format, args...);
format:格式化模板字符串。args:要插入到模板中的参数。
格式化占位符
| 占位符 | 含义 |
|---|---|
| %s | 字符串 |
| %d | 整数 |
| %f | 浮点数 |
| %c | 字符 |
| %b | 布尔值 |
| %n | 换行符(平台无关) |
String message = String.format( "姓名: %s, 年龄: %d" , "张三" , 25 ); System.out.println(message); // 输出: 姓名: 张三, 年龄: 25
格式化选项
可以使用格式化选项控制输出格式,例如宽度、对齐方式、精度等。
// 控制浮点数小数位数 double value = 3.1415926 ; String result = String.format( "保留两位小数: %.2f" , value); System.out.println(result); // 输出: 保留两位小数: 3.14 // 控制宽度和对齐 String aligned = String.format( "%10s" , "Hello" ); // 右对齐,总宽度为10 System.out.println(aligned); // 输出: Hello
应用场景
- 日志记录:构建结构化的日志信息。
- 数据展示:格式化输出用户信息、金额、日期等。
- 调试输出:生成可读性更强的调试信息。
public void logInfo (String user, String action) { String log = String.format( "[INFO] 用户 %s 执行了操作: %s" , user, action); System.out.println(log); }
注意事项
- 性能问题:在高频调用的代码路径中,频繁使用
String.format可能会带来性能开销。建议在性能敏感场景中优先使用StringBuilder或其他高效拼接方式。 - 线程安全:
String.format是线程安全的,因为它不依赖共享状态。 - 国际化支持:可以通过
Locale参数指定格式化时使用的语言环境。
String formatted = String.format(Locale.US, "金额: $%.2f" , 12345.678 ); System.out.println(formatted); // 输出: 金额: $12345.68
七、MessageFormat格式化
MessageFormat 是 Java 中用于格式化字符串的高级工具,特别适合处理带有动态参数的复杂文本。它支持多种格式化选项,包括日期、数字和字符串等,并且可以实现多语言环境下的消息格式化。
String formatted = MessageFormat.format(pattern, arguments);
pattern:包含占位符的模板字符串。arguments:要替换到模板中的参数。
占位符语法
MessageFormat 的占位符使用 {index} 表示,例如 {0}, {1} 等,表示对应的参数索引。
String pattern = "姓名: {0}, 年龄: {1}" ; String result = MessageFormat.format(pattern, "张三" , 25 ); System.out.println(result); // 输出: 姓名: 张三, 年龄: 25
类型格式化
MessageFormat 支持对参数进行类型格式化,比如日期、数字等。
| 格式 | 含义 |
|---|---|
| {index, type} | 指定类型格式化 |
| {index, type, style} | 指定类型和样式 |
Date now = new Date (); String pattern = "当前时间: {0, date, yyyy-MM-dd HH:mm:ss}" ; String result = MessageFormat.format(pattern, now); System.out.println(result); // 输出: 当前时间: 2025-04-05 12:34:56 double amount = 12345.6789 ; String pattern = "金额: {0, number, currency}" ; String result = MessageFormat.format(pattern, amount); System.out.println(result); // 输出: 金额: ¥12,345.68(根据本地化显示)
多语言支持(国际化)
MessageFormat 可以结合 Locale 实现多语言消息格式化,适用于国际化场景。
Locale locale = Locale.US; String pattern = "Hello, {0}! You have {1} new messages." ; String result = MessageFormat.format(pattern, locale, "Alice" , 5 ); System.out.println(result); // 输出: Hello, Alice! You have 5 new messages.
动态参数替换
MessageFormat 支持传入数组或 Object[] 进行参数替换,适用于不确定参数数量的场景。
Object[] args = { "Alice" , 5 }; String pattern = "用户: {0}, 新消息数: {1}" ; String result = MessageFormat.format(pattern, args); System.out.println(result); // 输出: 用户: Alice, 新消息数: 5
应用场景
| 场景 | 使用方式 |
|---|---|
| 日志记录 | 构建结构化的日志信息,支持动态参数。 |
| 国际化消息 | 结合 ResourceBundle 提供多语言支持。 |
| 报表生成 | 生成带格式的数据展示内容。 |
| 异常信息格式化 | 构建可读性强的错误提示信息。 |
注意事项
- 性能开销:相比
String.format,MessageFormat性能略低,建议在需要复杂格式化或国际化时使用。 - 线程安全:
MessageFormat不是线程安全的,多线程环境下应避免共享实例。 - 资源管理:在频繁使用的场景中,建议缓存
MessageFormat实例以提高性能。
与 String.format 对比
| 特性 | MessageFormat | String.format |
|---|---|---|
| 占位符 | {0}, {1} | %s, %d |
| 国际化支持 | 支持 | 不支持 |
| 类型格式化 | 支持日期、货币等 | 支持基本类型 |
| 性能 | 相对较低 | 更高 |
| 线程安全 | 非线程安全 | 线程安全 |
综合示例
public void formatUserMessage () { String pattern = "用户: {0}, 登录时间: {1, date, yyyy-MM-dd HH:mm:ss}, 尝试次数: {2}" ; Date loginTime = new Date (); Object[] args = { "admin" , loginTime, 3 }; String message = MessageFormat.format(pattern, args); System.out.println(message); }
输出:
用户: admin, 登录时间: 2025-04-05 12:34:56, 尝试次数: 3
总结
MessageFormat 是一个功能强大且灵活的格式化工具,尤其适用于需要国际化支持和复杂格式化的场景。虽然其性能不如 String.format,但在需要处理多语言、日期、货币等复杂格式时,它是更合适的选择。
八、大文本处理方案
使用缓冲字符流,逐行读,逐行处理,即使内存只有几百M,也能逐步拆解处理几个GB的文件。
// 使用BufferedReader逐行读取大文件 public void processLargeFile (Path path) throws IOException { try ( BufferedReader reader = Files.newBufferedReader(path)) { String line; while ((line = reader.readLine()) != null ) { processLine(line); // 处理每一行 } } }
九、JVM调优
项目若经常处理大量文本、字符串,需要对字符串常量池进行有效监控,进行配置优化。
# 查看字符串驻留情况 jcmd <PID> VM.string_table_stats
JVM调优参数
| 参数 | 推荐值 | 适用场景 |
|---|---|---|
| -XX:+UseStringDeduplication | 开启 | 减少重复字符串内存占用 |
| -XX:StringTableSize=100000 | 自定义大小 | 大量字符串驻留需求 |
| -XX:+PrintStringTableStatistics | 启用 | 分析字符串常量池 |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)