JAVA进阶技术之五:JAVA 中字符串处理全解析,一文读懂!
小标题:玩 “转” Java 字符串:这些工具让你的代码妙笔生花
一、引言:字符串处理之重
在 JAVA编程的广袤天地里,字符串处理宛如一颗关键基石,稳稳地支撑着程序大厦的每一层构建。从严谨校验用户输入的每一个字符,到精细解析纷繁复杂的文本数据;从有条不紊地格式化日志信息,使其清晰可读,再到精美呈现界面上的每一段文本,字符串操作可谓无处不在。毫不夸张地说,其处理水平的高低,直接牵系着程序的性能优劣、功能强弱以及运行时的稳定与否。
二、类型转换:跨越数据鸿沟
** 基本与包装类型互转**:
// 自动装箱,恰似一位神奇的魔法师,能将 int 类型数据轻巧地变为 Integer,这在集合场景里可太实用啦!要知道,像 List 这样的集合,只能收纳对象,有了自动装箱,基本类型数据就能顺利“入驻”。
Integer num = 5;
// 拆箱呢,则像是解开包裹的过程,把 Integer 还原成 int,方便后续进行各种算术运算,获取最原始的数据值。
int primitiveNum = num.intValue();
这在集合存储数值时常用,例如:
List<Integer> numList = new ArrayList<>();
numList.add(10); // 看,自动装箱发挥作用啦,10 这个基本类型数据被自动转换成 Integer 对象,存入列表,一切就是这么自然流畅。
各类转字符串:
double d = 3.14;
// String.valueOf() 方法就如同一位精准的工匠,能把 double 型数据完美转换成对应字符串形式,原汁原味地保留原始精度,在需要展示数据的文本场景中,它可是不可或缺的得力助手。
String doubleStr = String.valueOf(d);
System.out.println(doubleStr);
class CustomObject {
private String name;
public CustomObject(String name) {
this.name = name;
}
// 重写 toString 方法,就像是给对象定制了一身华丽的外衣,让它以我们期望的自定义易读形式精彩亮相。
@Override
import java.text.SimpleDateFormat;
import java.util.Date;
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 借助 SimpleDateFormat,按照指定的 "yyyy-MM-dd" 格式,把当前日期巧妙转换成字符串,这在日志记录时,能让日期规整有序,数据存储时,也能确保日期格式统一,在后续查询与处理时就会便捷许多。
String dateStr = sdf.format(now);
System.out.println(dateStr);
try {
// 反过来,parse 方法又像一把精准的钥匙,能开启符合 "yyyy-MM-dd" 格式字符串的“时间大门”,将其完美解析为 Date 对象,如此一来,在进行日期相关的运算、比较时,就能得心应手。
Date parsedDate = sdf.parse("2024-01-01");
System.out.println(parsedDate);
} catch (Exception e) {
e.printStackTrace();
}
集合类型转换:
String[] array = {"a", "b", "c"};
// Arrays.asList() 方法好似一条便捷的通道,能迅速将数组转换为 List,让我们可以尽情利用 List 丰富多样的操作方法,无论是排序让数据井井有条,还是查找精准定位元素,能大幅提升数据处理的灵活性,为我们的编程工作减负增效。
List<String> list = Arrays.asList(array);
System.out.println(list);
List<Integer> anotherList = new ArrayList<>();
// Collections.addAll() 则像是一位贴心的管家,能一次性向已有空集合填充多个元素,避免了逐个添加的繁琐流程,快速完成集合内容的初始化,让数据整合变得轻松简单。
Collections.addAll(anotherList, 1, 2, 3);
System.out.println(anotherList);
通用对象转换:
try {
// 利用反射这一强大的“超能力”,只需通过类名,就能加载类并创建其实体,仿佛拥有了哆啦 A 梦的任意门,实现动态灵活的对象创建,在插件式架构、框架底层开发等前沿领域,常常能大显身手。
Object dateObj = Class.forName("java.util.Date").newInstance();
System.out.println(dateObj);
} catch (Exception e) {
e.printStackTrace();
}
三、截取:精准切割片段
subString 方法:
String file = "example.txt";
// 看这里,substring 方法化身一位精准的裁剪师,通过巧妙定位文件名中最后一个 '.' 的位置,干净利落地截取其后的字符串,在判断文件类型这类场景中,它可是一把“利器”,能快速帮我们识别文件的“身份”。
String suffix = file.substring(file.lastIndexOf('.'));
System.out.println(suffix);
StringUtils 截取:
import org.apache.commons.lang3.StringUtils;
String config = "key=value;anotherKey=anotherValue";
// StringUtils.substringBetween 方法如同一个精明的寻宝猎人,能便捷地抓取配置文件格式字符串中指定等号前后、分号之间的文本,精准提取关键信息,让配置解析工作变得轻松愉悦,仿佛开启了一场探秘之旅,关键宝藏尽收眼底。
String value = StringUtils.substringBetween(config, "=", ";");
System.out.println(value);
split 方法:
String csv = "a,b,c";
// split 方法依据逗号正则表达式,像一把锋利的手术刀,将 CSV 格式字符串精准分割,拆分为一个个字符串数组元素,这样我们就能逐个处理数据项,在数据导入导出这些频繁与数据文件打交道的场景中,它是我们最忠实的“伙伴”。
String[] parts = csv.split(",");
for (String part :
四、查找:定位目标字符
String 自带查找:
String input = "This is a sample text";
// contains 方法宛如一位严谨的安检员,仔细判断输入字符串是否包含特定单词 "sample",在文本筛选时,能帮我们快速甄别出符合条件的文本,校验用户输入是否合规时,也能严守关卡,确保输入无误。
boolean containsWord = input.contains("sample");
System.out.println(containsWord);
int index = input.indexOf("is");
// indexOf 方法则像是一位经验丰富的导航员,能精准返回首次出现 "is" 的索引位置,有了它,我们在提取关键信息前后的文本时,就能沿着它指引的方向,顺利抵达目的地,进行下一步处理。
System.out.println(index);
int lastIndex = input.lastIndexOf("is");
// 而 lastIndexOf 方法就如同一位回溯时光的探险家,能找到最后一次出现 "is" 的位置,在处理重复子串、反向查找关键信息时,它总能带我们找到那隐藏在深处的“宝藏”,发挥意想不到的作用。
System.out.println(lastIndex);
Matcher 类查找:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String text = "Contact us at info@example.com";
Pattern pattern = Pattern.compile("\\w+@\\w+\\.\\w+");
Matcher matcher = pattern.matcher(text);
// 利用正则表达式结合 Matcher 类,仿佛开启了一场智能搜索之旅,精准匹配查找文本中的邮箱地址,无论是在纷繁复杂的网页文本里,还是用户随意投入的信息中,都能慧眼识珠,将邮箱地址准确提取出来。
while (matcher.find()) {
System.out.println(matcher.group());
}
StringBuilder 查找:
StringBuilder sb = new StringBuilder("abcdef");
// 在可变字符串构建的过程中,indexOf 方法同样能大显身手,它像一个敏锐的探测器,查找指定子串 "cd" 的只位置,和 String 的查找功能类似,却又专为可变字符串打造,方便我们边构建边检查内容,确保每一步都万无一失。
int foundIndex = sb.indexOf("cd");
System.out.println(foundIndex);
五、替换:灵活修改文本
String.replace 方法:
String message = "Hello, world!";
// replace 方法如同一位妙手回春的文字医生,将字符串中的 "world" 子串迅速替换为 "Java",而且是全局替换哦!无论是文案优化,让文字焕发出新的魅力,还是敏感词替换,守护文本的纯净,它都能轻松搞定。
String replaced = message.replace("word", "Java");
System.out.println(replaced);
可变字符串替换:
StringBuilder sb = new StringBuilder("abcdef");
// 对于 StringBuilder,它的 replace 方法就像是一位精细的修补匠,能对指定区间 [2, 4) 的字符进行精准替换,将其变为 "XX",在不产生额外临时字符串的情况下,高效修改文本,让可变字符串的编辑变得得心应手,游刃有余。
sb.replace(2, 4, "XX");
System.out.println(sb.toString());
StringBuffer sbf = new StringBuffer("abccef");
// 同样的操作,StringBuffer 也不在话下,它在多线程场景下可是守护可变字符串修改的“安全卫士”,确保数据安全稳定,即使面对多线程并发修改,也能稳如泰山。
sbf.replace(2, 4, "YY");
System.out.println(sbf.toString());
正则替换:
String text = "123abc456";
// replaceAll 方法借助正则表达式的强大力量,如同一位强力的清洁大师,去除文本中的所有数字,将文本格式清理得干干净净,只留下字母部分,在数据预处理环节,能为后续精准分析数据扫除障碍,文本规范化时,也能让文本整齐划一。
String cleanText = text.replaceAll("\\d", "");
System.out.println(cleanText);
String firstReplaced = text.replaceFirst("\\d", "X");
// 而 replaceFirst 方法则像是一位巧妙的标记员,仅替换首次出现的数字为 "X",在部分修改文本、标记首次出现关键信息时,它总能恰到好处地完成任务,不多不少,精准到位。
System.out.println(firstReplaced);
六、StringBuilder 与 StringBuffer:异同剖析
相同点上,它们都提供诸如追加、插入、删除字符等丰富方法,方便开发者灵活构建与修改字符串内容,以此避开 String 类不可变性带来的性能损耗。像拼接大量短字符串时,若用 String 反复相加,会产生众多无用中间对象,而它们能高效应对。
不同之处显著,StringBuffer 是线程安全的,其内部方法多被 synchronized 关键字修饰,在多线程并发访问、修改同一字符序列时,能确保数据一致性,不过这也带来一定性能开销。与之相反,StringBuilder 不考虑线程同步问题,执行速度更快,适用于单线程环境,如本地方法内对字符串的快速处理。开发时,若程序运行在多线程且涉及字符串频繁变动,StringBuffer 是可靠选择;单线程情形下,追求极致性能,StringBuilder 则更为妥当。 总之,了解二者特性,能助开发者依场景优化代码,提升程序效率。
七、字符串应用案例
案例一:批量替换文本中的特定词汇
假设我们正在编辑一篇科技文章,文中多次提及 “algorithm”,但现在需要根据特定的出版规范,将所有的 “algorithm” 替换为 “algorithmic method”。
public class TextEditorExample1 {
public static void main(String[] args) {
String document = "The advanced algorithm can solve complex problems. Another application of the algorithm is in data analysis.";
String targetWord = "algorithm";
String replacementWord = "algorithmic method";
String replacedDocument = document.replaceAll(targetWord, replacementWord);
System.out.println(replacedDocument);
}
}
在这个案例中,我们使用 replaceAll 方法,它会在整个文档字符串中查找所有匹配 “algorithm” 的地方,并一次性将它们全部替换为 “algorithmic method”,使得文本符合出版要求。
案例二:有条件地替换部分匹配的字符串
考虑一个场景,文本编辑器中存有一份学生成绩报告,其中成绩是以 “Score: XX” 的格式记录(XX 为具体分数),现在我们要将分数低于 60 分的成绩标记为 “Failed: XX”。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TextEditorExample2 {
public static void main(String[] args) {
String report = "Student 1: Score: 85, Student 2: Score: 45, Student 3: Score: 72";
Pattern pattern = Pattern.compile("Score: (\\d+)");
Matcher matcher = pattern.matcher(report);
StringBuffer modifiedReport = new StringBuffer();
while (matcher.find()) {
int score = Integer.parseInt(matcher.group(1));
if (score < 60) {
matcher.appendReplacement(modifiedReport, "Failed: " + score);
} else {
matcher.appendReplacement(modifiedReport, matcher.group());
}
}
matcher.appendTail(modifiedReport);
System.out.println(modifiedReport.toString());
}
}
这里,我们首先使用正则表达式来匹配成绩部分,然后通过 Matcher 的相关方法结合条件判断,对低于 60 分的成绩进行替换,其他成绩保持不变,最终得到标记后的成绩报告。
案例三:在 HTML 代码片段中替换属性值
以下是一段简单的 HTML 结构,页面中有一张图片,初始的 src 属性指向一张默认图片,我们将通过 JavaScript 代码来替换它的 src 属性值,使其指向另外一张图片: html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Replace Attribute Value Example</title>
</head>
<body>
<img id="myImage" src="default_image.jpg" alt="Default Image">
<button onclick="changeImageSrc()">更换图片</button>
<script>
function changeImageSrc() {
// 通过id选择器获取图片元素
var imageElement = document.getElementById('myImage');
if (imageElement) {
// 修改src属性值为新的图片路径
imageElement.src = 'new_image.jpg';
}
}
</script>
</body>
</html>
在上述代码中: 首先在 HTML 的
部分定义了一个