Java进阶实战 | 4道经典案例从String玩转ArrayList
适合人群:掌握了Java基础语法,正在学习String API和ArrayList集合的同学
涉及知识点:String常用方法(equals、split、contains、charAt)、StringBuilder、Scanner交互、ArrayList增删改查、循环控制技巧、Java文本块
阅读时长:约15分钟
目录
- 案例一:用户登录系统(3次机会)
- 案例二:String实现随机验证码
- 案例三:ArrayList批量删除技巧
- 案例四:ArrayList书籍管理系统
- 总结与知识体系
案例一:用户登录系统(3次机会)
问题描述
系统正确的登录名和密码是杳杉/666,请在控制台开发一个登录界面,接收用户输入的登录名和密码,判断用户是否登录成功。登录成功后展示"欢迎进入系统!",最多给用户三次登录机会。
解题思路
- 用
for循环控制最多3次尝试 - 每次用
Scanner.nextLine()接收一行输入,split(" ")拆分用户名和密码 - 将登录逻辑封装为
login()方法,返回不同结果字符串 - 登录成功 → 打印欢迎语 +
break退出 - 登录失败 → 提示剩余次数,3次用完直接结束
代码实现
package org.example; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); for (int i = 0; i < 3; i++) { // 1. 接收用户输入 System.out.println("请输入登录名和密码(以空格隔开):"); String temp = sc.nextLine(); String[] arr = temp.split(" "); String userName = arr[0]; String userPassWord = arr[1]; // 2. 登录逻辑 String result = login(userName, userPassWord); if ("success".equals(result)) { System.out.println("欢迎进入系统!"); break; } else { System.out.println(2 - i == 0 ? "登录失败!" : result + "!您还剩下" + (2 - i) + "次机会"); } } } public static String login(String loginName, String passWord) { // 定义正确账号和密码 String okLoginName = "杳杉"; String okPassWord = "666"; // 判断账号和密码 if (okLoginName.equals(loginName)) { if (okPassWord.equals(passWord)) { return "success"; } else { return "登录密码错误"; } } else { return "登录账号错误"; } } }运行结果
请输入登录名和密码(以空格隔开): admin 111 登录账号错误!您还剩下2次机会 请输入登录名和密码(以空格隔开): 杳杉 000 登录密码错误!您还剩下1次机会 请输入登录名和密码(以空格隔开): 杳杉 123456 欢迎进入系统!知识点小结
| 知识点 | 代码体现 | 说明 |
|---|---|---|
String.equals() | okLoginName.equals(loginName) | 字符串内容比较,不能用== |
String.split() | temp.split(" ") | 按分隔符拆分字符串为数组 |
"常量".equals(变量) | "success".equals(result) | 常量在前避免 NPE |
for+break | 循环3次,成功则break | 限制次数的经典写法 |
| 剩余次数计算 | 2 - i | i从0开始,第1次剩余2次 |
案例二:String实现随机验证码
问题描述
使用 String 来开发验证码,实现随机产生验证码,验证码的每位可能是数字、大写字母、小写字母。
解题思路
- 准备一个包含所有可能字符的 String 字符池(大小写字母 + 数字)
- 循环 n 次,每次从字符池中随机取一个字符
- 用
StringBuilder.append()拼接,效率高于String += Random.nextInt(code.length())生成随机索引,charAt(ind)取字符
代码实现
package org.example; import java.util.Random; public class Main { public static void main(String[] args) { System.out.println("输出 5 位长度的验证码: " + randomCode(5)); System.out.println("输出 8 位长度的验证码: " + randomCode(8)); } public static StringBuilder randomCode(int n) { StringBuilder s = new StringBuilder(); Random r = new Random(); // 字符池:小写字母 + 大写字母 + 数字 String code = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (int i = 0; i < n; i++) { int ind = r.nextInt(code.length()); s.append(code.charAt(ind)); } return s; } }运行结果
输出 5 位长度的验证码: K3m7Xa 输出 8 位长度的验证码: p2R9bN1c知识点小结
| 知识点 | 代码体现 | 说明 |
|---|---|---|
String.charAt(i) | code.charAt(ind) | 按索引取字符 |
Random.nextInt(n) | r.nextInt(code.length()) | 生成[0, n)随机数 |
StringBuilder | s.append(...) | 循环拼接首选,比+=高效 |
| 字符池思想 | String code = "abc...XYZ0-9" | 把可选字符集中管理,取用方便 |
对比:之前用
switch+ ASCII 码生成验证码Java基础实战 | 7道经典编程题详解(if分支、switch、数组、加密算法一网打尽),需要3个分支分别处理数字、大写、小写。这次用字符池方式,一行charAt搞定,代码更简洁、可读性更好。两种方式各有优势,switch方式更灵活(可以控制各类字符的比例),字符池方式更简洁。
案例三:ArrayList批量删除技巧
问题描述
购物车中存储了如下商品:python、python课程实战、JAVA、人工智能、Harness实战课程。现在用户想批量删除所有包含"python"的商品,请完成该需求。
解题思路
ArrayList 删除元素时有一个经典陷阱:删除后后面的元素会前移,导致索引变化。有两种正确做法:
方法一:正序遍历 + i–
- 删除后让
i回退一位,确保不漏掉紧挨着被删元素的下一个
方法二:倒序遍历(推荐)
- 从后往前遍历,删除元素不影响前面未遍历的索引
代码实现
package org.example; import java.util.ArrayList; public class Main { public static void main(String[] args) { // 方法一:正序遍历 + i-- ArrayList<String> ali = new ArrayList<>(); ali.add("python"); ali.add("python课程实战"); ali.add("JAVA"); ali.add("人工智能"); ali.add("Harness实战课程"); for (int i = 0; i < ali.size(); i++) { String name = ali.get(i); if (name.contains("python")) { ali.remove(name); i--; // 删除后回退索引,确保不漏数据 } } System.out.println("方法一结果: " + ali); System.out.println("----------------------------------------------"); // 方法二:倒序遍历(推荐) ArrayList<String> ali1 = new ArrayList<>(); ali1.add("python"); ali1.add("python课程实战"); ali1.add("JAVA"); ali1.add("人工智能"); ali1.add("Harness实战课程"); for (int i = ali1.size() - 1; i >= 0; i--) { String name = ali1.get(i); if (name.contains("python")) { ali1.remove(name); } } System.out.println("方法二结果: " + ali1); } }运行结果
方法一结果: [JAVA, 人工智能, Harness实战课程] ---------------------------------------------- 方法二结果: [JAVA, 人工智能, Harness实战课程]知识点小结
| 知识点 | 代码体现 | 说明 |
|---|---|---|
ArrayList.add() | ali.add("python") | 添加元素 |
ArrayList.get(i) | ali.get(i) | 按索引取元素 |
ArrayList.remove() | ali.remove(name) | 删除元素,后面的元素前移 |
String.contains() | name.contains("python") | 判断是否包含子串 |
| 删除陷阱 | 正序删除导致跳过 | 删除后索引变化,相邻元素被跳过 |
核心要点:删除元素时,正序遍历必须
i--,倒序遍历则天然安全。倒序遍历是首选,代码更简洁、不易出错。
案例四:ArrayList书籍管理系统
问题描述
完成书籍的上架、下架以及书籍信息浏览功能。用户通过菜单选择操作,系统响应执行。
解题思路
- 用
ArrayList<Book>存储书籍,比数组更灵活(动态扩容) addBook()— 上架:录入信息 → 校验 → 添加delBook()— 下架:按ID查找 → 删除showBook()— 浏览:遍历输出start()— 菜单入口:用switch分发操作
代码实现
实体类:Book.java
package org.example; public class Book { private int id; private String name; private String author; private String createTime; public Book() {} public Book(int id, String name, String author, String createTime) { this.id = id; this.name = name; this.author = author; this.createTime = createTime; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } @Override public String toString() { return id + "\t" + name + "\t" + author + "\t" + createTime; } }业务类:BookOperator.java
package org.example; import java.util.ArrayList; import java.util.Scanner; public class BookOperator { private ArrayList<Book> books = new ArrayList<>(); private Scanner sc = new Scanner(System.in); // 上架书籍 private void addBook() { System.out.println("请依次填入 id 名称 作者 出版日期(以空格隔开)"); sc.skip("\\s*"); String temp = sc.nextLine(); // 1. 检查空输入 if (temp == null || temp.trim().isEmpty()) { System.out.println("输入不能为null或空!"); return; } // 2. 分割字符串 String[] s = temp.trim().split("\\s+"); // 3. 检查字段数量 if (s.length != 4) { System.out.println("格式错误!需要4个字段,您输入了 " + s.length + " 个"); return; } // 4. 转换ID int id; try { id = Integer.parseInt(s[0].trim()); } catch (NumberFormatException e) { System.out.println("ID必须是数字!您输入的是:" + s[0]); return; } // 5. 检查ID是否已存在 for (Book b : books) { if (b.getId() == id) { System.out.println("ID '" + id + "' 已存在!"); return; } } // 6. 创建并添加书籍 books.add(new Book(id, s[1], s[2], s[3])); System.out.println("上架成功!"); } // 下架书籍 private void delBook() { System.out.print("请输入要下架书籍的ID:"); int id = sc.nextInt(); for (int i = 0; i < books.size(); i++) { if (books.get(i).getId() == id) { books.remove(i); System.out.println("书籍下架成功!"); return; } } System.out.println("未找到ID为 " + id + " 的书籍"); } // 展示所有书籍 private void showBook() { System.out.println("<图书管理系统所有书籍>"); System.out.println("编号\t书名\t\t\t作者\t\t创作时间"); System.out.println("------------------------------------------------"); for (int i = 0; i < books.size(); i++) { System.out.println(books.get(i)); } } // 菜单入口 public void start() { // 预置一本初始书籍 books.add(new Book(1, "Python编程快速上手", "Al Sweigart", "2021-03-15")); System.out.print( """ ==========图书管理系统============ 1. 上架书籍 2. 下架书籍 3. 展示所有书籍 ================================ 请输入您的操作: """); System.out.print("> "); int n = sc.nextInt(); switch (n) { case 1 -> addBook(); case 2 -> delBook(); case 3 -> showBook(); default -> System.out.println("您的输入有误!"); } } }测试类:Main.java
package org.example; public class Main { public static void main(String[] args) { BookOperator allBook = new BookOperator(); allBook.start(); } }运行结果
==========图书管理系统============ 1. 上架书籍 2. 下架书籍 3. 展示所有书籍 ================================ 请输入您的操作: > 3 <图书管理系统所有书籍> 编号 书名 作者 创作时间 ------------------------------------------------ 1 Python编程快速上手 Al Sweigart 2021-03-15知识点小结
| 知识点 | 代码体现 | 说明 |
|---|---|---|
ArrayList<Book> | private ArrayList<Book> books | 泛型集合,类型安全 |
split("\\s+") | temp.trim().split("\\s+") | 正则匹配多个空格 |
try-catch | Integer.parseInt(...) | 异常处理校验数字格式 |
toString()重写 | books.get(i)直接打印 | Book重写后可直接输出 |
Java文本块""" | 菜单字符串 | Java 15+ 特性,多行字符串 |
switch箭头语法 | case 1 -> addBook() | Java 14+ 增强,无需break |
总结与知识体系
四道案例知识点对照表
| 案例 | 核心知识点 | 关键API/技巧 |
|---|---|---|
| 用户登录 | String比较 + 循环控制 | equals()、split()、for+break |
| 验证码生成 | 字符池 + StringBuilder | charAt()、StringBuilder.append() |
| 批量删除 | ArrayList删除陷阱 | contains()、remove()、倒序遍历 |
| 书籍管理 | ArrayList综合应用 | add/remove/get、泛型、文本块、异常处理 |
从String到ArrayList的进阶路线
String(不可变字符串) │ equals / split / contains / charAt │ ▼ StringBuilder(可变字符串) │ append / 高效拼接 │ ▼ ArrayList(动态数组集合) │ add / remove / get / size │ ▼ 综合应用(书籍管理系统) 实体类 + 业务类 + 菜单交互编程思维总结
- 方法封装:登录逻辑封装为
login(),验证码封装为randomCode(),单一职责 - 删除安全意识:ArrayList边遍历边删除必须注意索引变化,倒序遍历最安全
- 输入校验意识:书籍上架时校验空输入、字段数量、ID格式、ID重复
- 字符串处理三板斧:
split拆分、contains判断包含、equals比较
ArrayList vs 数组对比
| 对比维度 | 数组Book[] | ArrayListArrayList<Book> |
|---|---|---|
| 长度 | 固定,创建时指定 | 动态扩容,自动增长 |
| 添加 | 需手动管理索引 | add()一行搞定 |
| 删除 | 需手动移动元素 | remove()自动调整 |
| 遍历 | for + length | for + size()或增强for |
| 适用场景 | 长度固定、性能优先 | 长度可变、开发效率优先 |
如果觉得有帮助,欢迎点赞 + 收藏 + 关注!后续会持续分享Java集合框架、IO流、多线程等进阶内容~
有问题欢迎评论区交流!