Java 实战:图书管理系统(ArrayList 应用)
Java-day20-5
一、项目需求分析
设计一个图书管理系统,支持图书信息的增删查、统计与排序功能,核心需求如下:
1. 使用 ArrayList 存储图书对象(封装书名、作者、价格属性);
2. 实现核心功能:添加图书、按书名删除图书、按书名查询价格、计算所有图书平均价格、按价格升序排序输出;
3. 通过控制台菜单与用户交互,支持重复操作直至选择退出;
4. 处理边界情况(如查询/删除不存在的图书、无图书时计算平均价格等)。
**技术选型**:
- 存储容器:ArrayList(动态数组,支持高效增删查改,适配图书列表管理场景);
- 数据封装:自定义 Book 实体类,封装图书核心属性;
- 交互方式:控制台菜单(Scanner 类);
- 核心技术:ArrayList 增删查方法、对象属性操作、集合排序(Collections.sort())、平均值计算。
二、项目实现步骤
2.1 图书实体类(Book.java)
首先定义图书实体类,封装书名、作者、价格属性,提供构造方法和 getter/setter 方法,重写 toString() 方便输出。
```java
/*** 图书实体类:封装图书信息(书名、作者、价格)*/public class Book {// 私有属性private String bookName; // 书名(唯一标识图书)private String author; // 作者private double price; // 价格// 构造方法public Book(String bookName, String author, double price) {this.bookName = bookName;this.author = author;this.price = price;}// getter/setter 方法public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}// 重写toString():自定义图书信息输出格式@Overridepublic String toString() {return "书名:《" + bookName + "》,作者:" + author + ",价格:" + price + " 元";}}```
2.2 核心功能实现(BookManagementSystem.java)
``java
import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.Scanner;/*** 图书管理系统:基于ArrayList实现图书的增删查、统计与排序*/public class BookManagementSystem {// 初始化ArrayList:存储图书对象private static ArrayList bookList = new ArrayList<>();private static Scanner scanner = new Scanner(System.in);public static void main(String[] args) {showMenu(); // 显示系统菜单}/*** 显示系统主菜单,接收用户选择并执行对应功能*/private static void showMenu() {while (true) {System.out.println("\n======= 图书管理系统 =======");System.out.println("1. 添加图书");System.out.println("2. 按书名删除图书");System.out.println("3. 按书名查询图书价格");System.out.println("4. 计算所有图书平均价格");System.out.println("5. 按价格升序排序并输出");System.out.println("6. 退出系统");System.out.print("请输入功能编号(1-6):");// 接收用户选择(处理非数字输入)int choice;try {choice = Integer.parseInt(scanner.nextLine().trim());} catch (NumberFormatException e) {System.out.println("输入无效!请输入1-6之间的数字。");continue;}// 根据选择执行对应功能switch (choice) {case 1:addBook();break;case 2:deleteBookByName();break;case 3:queryPriceByName();break;case 4:calculateAveragePrice();break;case 5:sortBooksByPriceAsc();break;case 6:System.out.println("退出系统成功!感谢使用~");scanner.close();System.exit(0);break;default:System.out.println("功能编号无效!请输入1-6之间的数字。");}}}/*** 功能1:添加图书*/private static void addBook() {System.out.println("\n======= 添加图书 =======");System.out.print("请输入书名:");String bookName = scanner.nextLine().trim();System.out.print("请输入作者:");String author = scanner.nextLine().trim();System.out.print("请输入价格(单位:元):");// 处理价格输入(必须为正数)double price;try {price = Double.parseDouble(scanner.nextLine().trim());if (priceSystem.out.println("价格无效!必须输入大于0的数字。");return;}} catch (NumberFormatException e) {System.out.println("价格输入无效!请输入数字。");return;}// 验证书名非空if (bookName.isEmpty() || author.isEmpty()) {System.out.println("书名和作者不能为空!添加失败。");return;}// 添加图书到集合bookList.add(new Book(bookName, author, price));System.out.println("图书添加成功!" + new Book(bookName, author, price));}/*** 功能2:按书名删除图书(支持模糊匹配?需求为“根据书名删除”,此处按精确匹配实现)*/private static void deleteBookByName() {System.out.println("\n======= 按书名删除图书 =======");if (bookList.isEmpty()) {System.out.println("当前图书库为空,无图书可删除!");return;}System.out.print("请输入要删除的图书书名(精确匹配):");String targetName = scanner.nextLine().trim();boolean isDeleted = false;// 遍历图书列表,查找并删除目标图书for (int i = 0; i < bookList.size(); i++) {Book book = bookList.get(i);if (book.getBookName().equals(targetName)) {bookList.remove(i); // 移除指定索引的图书System.out.println("删除成功!删除的图书信息:" + book);isDeleted = true;break; // 假设书名唯一,删除第一个匹配项后退出}}if (!isDeleted) {System.out.println("未找到书名为《" + targetName + "》的图书,删除失败。");}}/*** 功能3:按书名查询图书价格*/private static void queryPriceByName() {System.out.println("\n======= 按书名查询图书价格 =======");if (bookList.isEmpty()) {System.out.println("当前图书库为空,无图书可查询!");return;}System.out.print("请输入要查询的图书书名(精确匹配):");String targetName = scanner.nextLine().trim();boolean isFound = false;// 遍历图书列表,查找目标图书for (Book book : bookList) {if (book.getBookName().equals(targetName)) {System.out.println("查询结果:" + book);isFound = true;break; // 假设书名唯一}}if (!isFound) {System.out.println("未找到书名为《" + targetName + "》的图书。");}}/*** 功能4:计算所有图书的平均价格*/private static void calculateAveragePrice() {System.out.println("\n======= 计算所有图书平均价格 =======");if (bookList.isEmpty()) {System.out.println("当前图书库为空,无法计算平均价格!");return;}// 计算总价格double totalPrice = 0;for (Book book : bookList) {totalPrice += book.getPrice();}// 计算平均价格(保留2位小数)double averagePrice = totalPrice / bookList.size();System.out.printf("图书总数:%d 本,总价格:%.2f 元,平均价格:%.2f 元%n",bookList.size(), totalPrice, averagePrice);}/*** 功能5:按价格升序排序并输出图书信息*/private static void sortBooksByPriceAsc() {System.out.println("\n======= 按价格升序排序结果 =======");if (bookList.isEmpty()) {System.out.println("当前图书库为空,无图书可排序!");return;}// 创建临时列表进行排序,避免修改原列表顺序ArrayList sortedList = new ArrayList<>(bookList);// 按价格升序排序(使用Comparator匿名内部类)Collections.sort(sortedList, new Comparator() {@Overridepublic int compare(Book b1, Book b2) {// 处理double类型比较,避免精度问题return Double.compare(b1.getPrice(), b2.getPrice());}});// 输出排序后的图书信息System.out.println("排序结果(价格从低到高):");for (int i = 0; i < sortedList.size(); i++) {System.out.println((i + 1) + ". " + sortedList.get(i));}}}```
三、核心技术解析
3.1 ArrayList 核心操作
- **添加图书**:通过 add() 方法将新创建的 Book 对象存入 ArrayList,动态扩容无需手动管理容量;
- **删除图书**:通过 get(index) 遍历列表,找到目标图书后调用 remove(index) 移除(按索引删除效率更高);
- **查询图书**:增强 for 循环遍历列表,通过 getBookName() 匹配书名,查找目标图书;
- **排序处理**:创建原列表的副本进行排序,避免修改原数据顺序,通过 Collections.sort() 结合 Comparator 实现自定义排序规则。
3.2 实体类封装思想
- 自定义 Book 类,将图书的属性(书名、作者、价格)私有化,通过 getter/setter 方法控制属性访问,保证数据安全性;
- 重写 toString() 方法,自定义图书信息的输出格式,简化打印逻辑。
3.3 排序实现逻辑
- 使用 Collections.sort() 方法对 ArrayList 进行排序,传入 Comparator 匿名内部类自定义排序规则;
- 通过 Double.compare(b1.getPrice(), b2.getPrice()) 实现价格升序排序,避免直接使用 - 运算导致的精度问题;
- 排序前创建原列表的副本(new ArrayList<>(bookList)),确保原列表的顺序不被修改,符合实际使用场景。
3.4 边界情况处理
- 空列表校验:所有功能执行前先判断 bookList.isEmpty(),避免无图书时执行无效操作;
- 输入校验:价格必须为大于0的数字,书名/作者不能为空,非数字功能编号给出友好提示;
- 查找/删除失败提示:当未找到目标图书时,明确告知用户结果,提升交互体验。
四、运行效果演示
4.1 主菜单展示
======= 图书管理系统 =======
1. 添加图书
2. 按书名删除图书
3. 按书名查询图书价格
4. 计算所有图书平均价格
5. 按价格升序排序并输出
6. 退出系统
请输入功能编号(1-6):
4.2 功能1:添加图书
======= 添加图书 =======
请输入书名:Java编程思想
请输入作者:Bruce Eckel
请输入价格(单位:元):108.0
图书添加成功!书名:《Java编程思想》,作者:Bruce Eckel,价格:108.0 元
======= 添加图书 =======
请输入书名:SpringBoot实战
请输入作者:Craig Walls
请输入价格(单位:元):89.0
图书添加成功!书名:《SpringBoot实战》,作者:Craig Walls,价格:89.0 元
======= 添加图书 =======
请输入书名:MySQL必知必会
请输入作者:Ben Forta
请输入价格(单位:元):59.0
图书添加成功!书名:《MySQL必知必会》,作者:Ben Forta,价格:59.0 元
4.3 功能3:查询图书价格
======= 按书名查询图书价格 =======
请输入要查询的图书书名(精确匹配):Java编程思想
查询结果:书名:《Java编程思想》,作者:Bruce Eckel,价格:108.0 元
4.4 功能4:计算平均价格
======= 计算所有图书平均价格 =======
图书总数:3 本,总价格:256.00 元,平均价格:85.33 元
4.5 功能5:按价格升序排序
======= 按价格升序排序结果 =======
排序结果(价格从低到高):
1. 书名:《MySQL必知必会》,作者:Ben Forta,价格:59.0 元
2. 书名:《SpringBoot实战》,作者:Craig Walls,价格:89.0 元
3. 书名:《Java编程思想》,作者:Bruce Eckel,价格:108.0 元
4.6 功能2:删除图书
======= 按书名删除图书 =======
请输入要删除的图书书名(精确匹配):SpringBoot实战
删除成功!删除的图书信息:书名:《SpringBoot实战》,作者:Craig Walls,价格:89.0 元
4.7 功能6:退出系统
请输入功能编号(1-6):6
退出系统成功!感谢使用~
五、扩展功能与优化
5.1 支持书名模糊查询/删除
当前实现为精确匹配书名,可修改查询/删除逻辑,支持模糊匹配(包含目标关键词即视为匹配):
```java
// 模糊查询示例(修改queryPriceByName方法)for (Book book : bookList) {if (book.getBookName().contains(targetName)) { // 包含关键词即匹配System.out.println("查询结果:" + book);isFound = true;}}```
5.2 去重添加(避免重复书名)
添加图书时校验是否已存在相同书名,避免重复添加:
```java
// 添加图书前校验for (Book book : bookList) {if (book.getBookName().equals(bookName)) {System.out.println("已存在书名《" + bookName + "》的图书,添加失败。");return;}}5.3 支持按价格降序排序在排序功能中增加排序方向选择,支持升序/降序切换:javaSystem.out.print("请选择排序方向(1-升序,2-降序):");int sortDir = Integer.parseInt(scanner.nextLine().trim());Collections.sort(sortedList, new Comparator() {@Overridepublic int compare(Book b1, Book b2) {if (sortDir == 1) {return Double.compare(b1.getPrice(), b2.getPrice()); // 升序} else {return Double.compare(b2.getPrice(), b1.getPrice()); // 降序}}});```
5.4 持久化存储(文件/数据库)
当前图书数据仅存储在内存中,程序重启后丢失,可扩展为文件存储(如txt、JSON)或数据库存储(如MySQL),实现数据持久化。
六、总结:项目实战要点
1. **ArrayList 应用场景**:适合需要动态存储对象、频繁进行增删查操作的场景,图书管理系统中通过 ArrayList 高效管理图书列表;
2. **面向对象封装**:通过 Book 实体类封装图书属性,降低代码耦合度,提高代码可读性和维护性;
3. **核心逻辑设计**:
- 增删查:基于 ArrayList 的遍历和索引操作实现,结合属性匹配查找目标图书;
- 统计排序:通过遍历计算总价格实现平均值统计,使用 Collections.sort() 结合 Comparator 实现自定义排序;
4. **用户体验优化**:完善的输入校验、边界情况处理和友好的结果提示,让系统更易用、更健壮。
本项目覆盖了 ArrayList 集合的核心操作、实体类封装、集合排序等关键知识点,是 Java 基础集合实战的典型案例。通过扩展功能的练习,可进一步加深对 Java 集合、面向对象编程的理解,为后续复杂系统开发奠定基础。
