ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java 常用语法极简通关(四):数组与字符串的常用操作

Java 常用语法极简通关(四):数组与字符串的常用操作

开篇:一个"巡检成绩表处理"程序

上一章的成绩统计里,数组已经露过脸了:int[] scores = {92, 85, ...}。这一章把它讲透,再把日常开发中刷屏的 String 方法一口气过完。还是先看一段完整程序——录入一组成绩,做排序展示、查最高最低、格式化输出一张简易成绩表:

public class ScoreTableApp { public static void main(String[] args) { // 1. 声明并初始化数组 int[] scores = {85, 92, 74, 66, 90}; String[] names = {"张伟", "李强", "王磊", "赵鹏", "陈刚"}; // 2. 求最高分、最低分、平均分 int max = scores[0]; int min = scores[0]; int sum = 0; for (int i = 0; i < scores.length; i++) { if (scores[i] > max) { max = scores[i]; } if (scores[i] < min) { min = scores[i]; } sum += scores[i]; } double avg = (double) sum / scores.length; // 3. 打印成绩表(拼接出整齐的表头) StringBuilder table = new StringBuilder(); table.append("===== 巡检成绩表 =====\n"); for (int i = 0; i < names.length; i++) { String name = names[i]; // 名字不足 3 个字的后面补空格对齐 if (name.length() < 3) { name = name + " "; } table.append(name).append(":").append(scores[i]).append(" 分\n"); } System.out.print(table.toString()); // 4. 输出统计结论 System.out.println("最高分:" + max + ",最低分:" + min + ",平均分:" + avg); // 5. 找出第一个优秀者的名字 for (int i = 0; i < scores.length; i++) { if (scores[i] >= 90) { System.out.println("首个优秀者:" + names[i].trim()); break; } } } }

运行结果:

===== 巡检成绩表 ===== 张伟 :85 分 李强 :92 分 王磊 :74 分 赵鹏 :66 分 陈刚 :90 分 最高分:92,最低分:66,平均分:81.4 首个优秀者:李强

程序里涉及三样东西:数组、String 方法、StringBuilder,分三部分讲。

第一部分:数组——定长的同类型容器

声明与初始化的两种姿势

// 姿势一:声明时直接给值(最常用) int[] scores = {85, 92, 74, 66, 90}; // 姿势二:只给长度,元素拿默认值 int[] arr = new int[5]; // 5 个元素,全是 0 String[] names = new String[3]; // 3 个元素,全是 null

要点:

  • int[]是一个整体——"int 的数组"这种类型。数组可以装基本类型,也可以装引用类型。

  • new int[5]创建后元素自动填默认值:int 是 0,double 是 0.0,boolean 是 false,引用类型(包括 String)是 null

  • 数组长度创建时定死,之后不能变。这是数组最大的局限,也是后来 ArrayList(第九章)登场的理由。

三件套:下标、length、遍历

scores[0] // 取第一个元素,下标从 0 开始 scores.length // 长度:5(注意:数组的 length 是属性,没有括号) scores[i] = 100; // 按下标赋值

遍历的两种写法(第三章已讲,这里对号入座):

for (int i = 0; i < scores.length; i++) { ... } // 要下标用经典 for for (int s : scores) { ... } // 纯取值用增强 for

必知坑:数组越界(ArrayIndexOutOfBoundsException)

下标的合法范围是0 到 length-1,访问scores[5](长度就是 5 时)运行期直接抛异常:

int[] scores = {85, 92, 74}; System.out.println(scores[3]); // 编译能过,运行崩溃:ArrayIndexOutOfBoundsException

这类异常是新手期最常见的运行时报错。越界十有八九来自i <= scores.length这种边界写错,记住标准姿势是< length

顺带一提:多维数组(如int[][] matrix)存在,但业务代码里用得很少,软考偶尔露脸,知道int[3][4]是 3 行 4 列即可,本系列不展开。

第二部分:String 的常用方法——就这一把,天天用

String 类的方法有几十个,日常高频的如下表,结合案例逐个看:

方法作用例子
length()字符个数"锚杆".length()→ 2
charAt(i)取下标 i 的字符"锚杆".charAt(0)'锚'
substring(a, b)截取 [a, b) 区间"设备巡检".substring(0, 2)"设备"
indexOf(str)找子串首次出现的位置"3号皮带".indexOf("皮带")→ 2
contains(str)是否包含子串"井下-580m".contains("580")→ true
equals(str)内容比较第二章铁律
equalsIgnoreCase(str)忽略大小写比较"abc".equalsIgnoreCase("ABC")→ true
trim()去掉首尾空白" 维修 ".trim()"维修"
split(分隔符)拆成字符串数组"85,92,74".split(",")["85","92","74"]
replace(旧, 新)替换全部匹配"a-b-c".replace("-", "/")"a/b/c"
startsWith / endsWith前缀/后缀判断文件名、编号判断常用
toUpperCase / toLowerCase大小写转换统一格式用

结合案例看几个典型的:

① 名字对齐用的length()

if (name.length() < 3) { name = name + " "; // 不足 3 字补空格,表格才齐 }

注意区分:数组的 length 是属性(scores.length),String 的 length 是方法(name.length()。带不带括号是经典笔误点,也是考点。

② 解析 CSV 风格的数据,split()+trim()是黄金搭档

String line = " 张伟 , 92 , 综采一队 "; String[] parts = line.split(","); String name = parts[0].trim(); // "张伟" int score = Integer.parseInt(parts[1].trim()); // 92(字符串转 int,第十章细讲)

③ 判断后再截取,indexOf()配合substring()

String location = "井下-580m东翼大巷"; int idx = location.indexOf("m"); if (idx >= 0) { // indexOf 找不到会返回 -1,先判断 String depth = location.substring(3, idx + 1); // "580m" }

④ 前缀判断处理编号

String code = "WX-2026-0341"; if (code.startsWith("WX-")) { System.out.println("这是一条维修单"); }

别忘了第二章讲过的 String 不可变性:这些方法全部返回新字符串,原字符串纹丝不动name.trim()之后要把结果接回来——name = name.trim();,光调用不接收等于白调用。

第三部分:StringBuilder——循环拼接的唯一正确姿势

案例里拼成绩表用的是 StringBuilder:

StringBuilder table = new StringBuilder(); table.append("===== 巡检成绩表 =====\n"); for (int i = 0; i < names.length; i++) { table.append(name).append(":").append(scores[i]).append(" 分\n"); } System.out.print(table.toString());

为什么不用熟悉的+?回顾第二章:String 不可变,每次+都新建一个对象。循环 1000 次就产生 1000 个临时字符串对象,内存和速度都是浪费。StringBuilder 内部是一块可变的字符缓冲区append是原地追加,不产生新对象,最后toString()一次成型。

用法就三个动作:

StringBuilder sb = new StringBuilder(); // 1. 创建 sb.append("a").append(100).append("b"); // 2. 追加(可链式,什么类型都能塞) String result = sb.toString(); // 3. 转成 String

规则一句话:循环里拼字符串,用 StringBuilder;一次性拼两三个,用+就行(编译器对简单的+拼接有优化,不用矫枉过正)。

案例里还有个细节:\n是换行符(转义字符)。常用的转义就三个:\n换行、\t制表符、\"在字符串里表示一个双引号本身。

一个隐患:两个数组"按下标对应"有多脆弱?

回头看案例的数据结构:

int[] scores = {85, 92, 74, 66, 90}; String[] names = {"张伟", "李强", "王磊", "赵鹏", "陈刚"};

"张伟得 85 分"这个关系,靠的是两个数组下标对齐来维系的:names[i] 的成绩是 scores[i]。程序跑对的前提是录入时两边顺序严格一致。

问题在于:这种对应关系编译器完全不管。假设录入时手一抖,names 里漏了一个人或者顺序排错,程序照样编译通过、照样运行,只是从此以后"李强的成绩"全是别人的——结果张冠李戴,还不会有任何报错提示。这是数组时代最隐蔽的逻辑 bug 温床。

解法其实直觉上很简单:把"姓名、成绩、班组"捆在一起,装进一个"工人"里,让它们物理上不可分。这个"捆在一起"的手段,就是下一章的主角——类与对象

常踩的坑(排雷清单)

  1. 数组越界:下标合法范围 0 ~ length-1,边界一律写i < length

  2. length 带不带括号:数组scores.length(属性),Stringname.length()(方法),记死这个区别。

  3. String 方法不接收返回值s.trim()之后 s 没变!字符串不可变,必须s = s.trim()

  4. substring 的右边界不含substring(0, 2)取下标 0 和 1,左闭右开,和很多人的直觉相反。

  5. indexOf 找不到返回 -1:直接用返回值当下标会越界,先判>= 0

  6. 循环里用+拼长字符串:几百上千次循环后性能明显下降,该上 StringBuilder。

  7. 多数组按下标对应:数据错位不报错,是最隐蔽的逻辑 bug 温床。

本章小结

  • 数组:定长、同类型;两种初始化姿势;元素默认值(int 为 0、引用为 null);越界是运行时异常。

  • String 高频方法就那一把:length()substring()indexOf()contains()trim()split()replace()startsWith等,全部返回新串。

  • StringBuilder:newappendtoString()三步,循环拼接的唯一正确姿势。

  • 数组按下标对应多份数据的痛点,引出了下一章的主角。

下一章是全系列的地基:类与对象——字段、方法、构造器、this 与 static。我们会把"姓名+成绩+班组"封装成一个真正的"工人对象",亲手解决本章结尾的数据错位问题。

返回列表