尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java控制台员工管理系统:ArrayList实现CRUD全流程

Java控制台员工管理系统:ArrayList实现CRUD全流程 简介这是一份面向Java初学者的控制台版员工管理系统实战项目聚焦基础集合操作与面向对象编程实践适用于高校课程设计、自学练手及Java入门项目训练。资源以ArrayList为核心数据结构完整实现员工信息的增删改查、按工号查询、按部门筛选及薪资修改等6项核心功能代码逻辑清晰经多次测试运行稳定。压缩包共9个文件包含3个Java源文件含主程序EmpManager及员工实体类、3个编译后class文件、1个.classpath配置文件、1个.project工程文件和1个.prefs偏好设置文件整体仅9KB轻量易导入Eclipse等IDE直接运行。已有860人学习下载提供可直接编译运行的完整工程结构、规范的类封装与控制台交互流程特别适合理解Java基础语法、集合应用与简单MVC分层思想的学习者上手实践。1. 控制台不是过时的摆设一个纯 Java 员工管理系统如何用 ArrayList 扛起 CRUD 全流程你可能在面试题里见过“用控制台写个学生管理系统”也听过“现在谁还写控制台程序”——但真实项目里课程设计、教学演示、快速原型验证、甚至嵌入式设备的调试接口控制台仍是不可替代的轻量级交互层。这个 Java 员工管理系统不依赖任何 GUI 框架或 Web 容器仅靠System.out.println和Scanner就完成增删改查、按部门筛选、按工号精准定位等六项核心操作背后是扎实的面向对象建模与集合类实战运用。它把ArrayListEmployee当作内存数据库用String工号作主键索引用for-each遍历实现部门过滤用removeIf()实现条件删除——没有 ORM没有 SQL却完整复现了数据管理的本质逻辑。适合 Java 初学者巩固类封装、集合操作与输入校验也适合面试前快速梳理 CRUD 的底层实现路径尤其对理解“为什么 ArrayList 适合小规模内存管理”“何时该用 equals() 而非 ”“Scanner.nextLine() 为何要吃掉换行符”这类基础但易错点有直接可跑的上下文。2. 从 Employee 类建模到 ArrayList 存储面向对象结构如何支撑业务逻辑2.1 Employee 类的设计原则与字段约束员工信息包含工号、姓名、职位、年龄、月薪、部门六个属性其中工号id必须唯一且不可为空年龄需为正整数月薪应大于零——这些约束不能只靠文档说明而要通过构造方法和 setter 强制校验。Employee类不是简单地定义 public 字段而是采用私有字段 公共 getter/setter 的标准封装模式并在 setter 中嵌入业务规则public class Employee { private String id; private String name; private String position; private int age; private double salary; private String department; public Employee(String id, String name, String position, int age, double salary, String department) { if (id null || id.trim().isEmpty()) { throw new IllegalArgumentException(工号不能为空); } if (age 0) { throw new IllegalArgumentException(年龄必须大于0); } if (salary 0) { throw new IllegalArgumentException(月薪必须大于0); } this.id id.trim(); this.name name null ? : name.trim(); this.position position null ? : position.trim(); this.age age; this.salary salary; this.department department null ? : department.trim(); } // getter 方法省略均返回对应私有字段 public String getId() { return id; } public String getName() { return name; } public String getPosition() { return position; } public int getAge() { return age; } public double getSalary() { return salary; } public String getDepartment() { return department; } // setter 方法中加入校验以 setSalary 为例 public void setSalary(double salary) { if (salary 0) { throw new IllegalArgumentException(月薪必须大于0); } this.salary salary; } }提示构造方法中对id和salary的校验避免了后续查询时因空值或非法数值导致NullPointerException或逻辑错误trim()处理用户输入首尾空格防止“001 ”和“001”被当作不同工号。2.2 ArrayList 作为内存数据库的选型依据与初始化策略系统使用ArrayListEmployee存储所有员工而非LinkedList或HashSet原因明确随机访问高频按工号查询getById、按部门筛选findByDepartment都需要遍历并比较ArrayList的 O(1) 随机访问优于LinkedList的 O(n)插入顺序敏感员工录入顺序即列表索引顺序符合“先录入先显示”的自然预期无重复需求工号唯一性由业务逻辑保证无需HashSet的去重能力反而ArrayList更易调试可直接list.get(i)查看第 i 条内存开销可控课程设计场景员工数通常 1000ArrayList的扩容机制1.5 倍完全满足。初始化在EmpManager主类中完成import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class EmpManager { private static ListEmployee employees new ArrayList(); // 静态变量全局共享 private static Scanner scanner new Scanner(System.in); public static void main(String[] args) { // 启动菜单循环 while (true) { showMenu(); int choice getIntInput(请选择操作1-6); switch (choice) { case 1: addEmployee(); break; case 2: findEmployeeById(); break; case 3: findEmployeesByDepartment(); break; case 4: listAllEmployees(); break; case 5: deleteEmployeeById(); break; case 6: updateSalaryById(); break; case 0: System.out.println(退出系统再见); return; default: System.out.println(无效选项请重新输入。); } } } private static void showMenu() { 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.println(0. 退出系统); System.out.print(请输入选择); } }注意employees声明为static是为了在多个静态方法间共享数据避免每次调用都新建实例scanner同样静态化确保输入流不被意外关闭。2.3 输入校验与 Scanner 使用陷阱规避控制台输入极易因格式错误崩溃getIntInput()和getStringInput()封装了常见容错逻辑private static int getIntInput(String prompt) { while (true) { System.out.print(prompt); try { return Integer.parseInt(scanner.nextLine().trim()); } catch (NumberFormatException e) { System.out.println(输入格式错误请输入整数); } } } private static String getStringInput(String prompt) { while (true) { System.out.print(prompt); String input scanner.nextLine().trim(); if (!input.isEmpty()) { return input; } System.out.println(输入不能为空请重新输入); } }关键细节scanner.nextLine()必须成对使用。若在nextInt()后直接调用nextLine()会读取残留的换行符导致跳过输入——因此所有数字输入统一用nextLine()parseInt彻底规避此坑。3. 六大功能模块的实现逻辑与边界条件处理3.1 添加员工构造函数校验 重复工号拦截添加操作需检查工号是否已存在避免数据冗余private static void addEmployee() { System.out.println(\n--- 添加员工 ---); String id getStringInput(请输入工号); // 检查工号是否已存在 boolean exists employees.stream() .anyMatch(emp - emp.getId().equals(id)); if (exists) { System.out.println(错误工号 id 已存在无法重复添加); return; } String name getStringInput(请输入姓名); String position getStringInput(请输入职位); int age getIntInput(请输入年龄); double salary getDoubleInput(请输入月薪); String department getStringInput(请输入所在部门); try { Employee emp new Employee(id, name, position, age, salary, department); employees.add(emp); System.out.println(✅ 员工 name 添加成功); } catch (IllegalArgumentException e) { System.out.println(❌ 添加失败 e.getMessage()); } } private static double getDoubleInput(String prompt) { while (true) { System.out.print(prompt); try { return Double.parseDouble(scanner.nextLine().trim()); } catch (NumberFormatException e) { System.out.println(输入格式错误请输入数字); } } }参数说明getDoubleInput()复用getIntInput()的容错思想将字符串转doublestream().anyMatch()替代传统 for 循环代码更简洁且语义清晰。3.2 按工号查询与按部门筛选两种遍历策略的性能对比查询功能体现ArrayList的线性查找本质private static void findEmployeeById() { String id getStringInput(请输入要查询的工号); Employee found null; for (Employee emp : employees) { if (emp.getId().equals(id)) { found emp; break; } } if (found ! null) { System.out.println(\n--- 查询结果 ---); printEmployee(found); } else { System.out.println(⚠️ 未找到工号为 id 的员工。); } } private static void findEmployeesByDepartment() { String dept getStringInput(请输入部门名称); ListEmployee result new ArrayList(); for (Employee emp : employees) { if (emp.getDepartment().equalsIgnoreCase(dept)) { result.add(emp); } } if (result.isEmpty()) { System.out.println(⚠️ 部门 dept 下无员工。); } else { System.out.println(\n--- 部门 dept 员工列表 ---); result.forEach(EmpManager::printEmployee); } } private static void printEmployee(Employee emp) { System.out.printf(工号%s | 姓名%s | 职位%s | 年龄%d | 月薪%.2f | 部门%s%n, emp.getId(), emp.getName(), emp.getPosition(), emp.getAge(), emp.getSalary(), emp.getDepartment()); }逻辑说明findEmployeeById()用break提前终止循环最坏时间复杂度 O(n)平均 O(n/2)findEmployeesByDepartment()必须遍历全部元素因部门非唯一故用ListEmployee收集结果再统一打印避免多次System.out.println降低 I/O 开销。3.3 删除与修改基于工号的精准定位与状态反馈删除操作需确认用户意图并处理未找到的情况private static void deleteEmployeeById() { String id getStringInput(请输入要删除的工号); boolean removed employees.removeIf(emp - emp.getId().equals(id)); if (removed) { System.out.println(✅ 工号 id 的员工删除成功); } else { System.out.println(⚠️ 未找到工号为 id 的员工删除失败。); } } private static void updateSalaryById() { String id getStringInput(请输入要修改薪资的工号); Employee target null; for (Employee emp : employees) { if (emp.getId().equals(id)) { target emp; break; } } if (target null) { System.out.println(⚠️ 未找到工号为 id 的员工。); return; } double newSalary getDoubleInput(请输入新薪资); try { target.setSalary(newSalary); System.out.println(✅ 员工 target.getName() 的薪资已更新为 newSalary); } catch (IllegalArgumentException e) { System.out.println(❌ 更新失败 e.getMessage()); } }参数说明removeIf()是 Java 8 引入的便捷方法内部调用Iterator.remove()比手动for循环 list.remove(i)更安全避免ConcurrentModificationExceptionsetSalary()的异常捕获确保非法薪资不会静默失败。4. 系统健壮性增强空指针防护、输入缓冲清理与运行时日志4.1 空集合与空指针的防御式编程listAllEmployees()在employees为空时需友好提示而非抛出NoSuchElementExceptionprivate static void listAllEmployees() { if (employees.isEmpty()) { System.out.println( 当前无员工信息。); return; } System.out.println(\n--- 所有员工信息 ---); int index 1; for (Employee emp : employees) { System.out.print([ index ] ); printEmployee(emp); } System.out.println(共 employees.size() 条记录。); }注意isEmpty()比size() 0更语义化且避免了size()方法在某些集合实现中可能的开销。4.2 Scanner 缓冲区残留问题的系统级修复Scanner在读取数字后遗留的换行符若未被nextLine()消费会导致后续getStringInput()直接返回空字符串。本系统通过统一使用nextLine()解决但需在main方法末尾显式关闭资源public static void main(String[] args) { try { // ... 主循环逻辑 } finally { scanner.close(); // 防止资源泄漏 } }提示scanner.close()关闭的是System.in流实际影响有限因System.in是静态输入源但属于良好实践避免 IDE 警告。4.3 运行时状态快照与调试辅助输出为便于验证数据一致性可在关键操作后添加简明日志操作类型日志示例触发时机添加成功✅ 员工张三添加成功工号EMP001addEmployee()成功分支查询命中 找到1条匹配记录EMP001findEmployeeById()找到时删除执行️ 已移除员工EMP001李四deleteEmployeeById()成功时空集合提示 当前无员工信息size0listAllEmployees()空时这些日志不依赖日志框架仅用System.out.println但通过 emoji 和括号标注关键信息大幅提升控制台可读性。5. 从控制台走向生产三个可立即落地的进阶改造技巧5.1 支持中文输入与 UTF-8 编码声明Windows 控制台默认编码为 GBK若员工姓名含生僻字如“龘”“靐”可能显示乱码。解决方案是在main方法开头强制设置控制台编码public static void main(String[] args) { // 强制设置控制台输出编码为 UTF-8 try { System.setOut(new java.io.PrintStream(System.out, true, UTF-8)); } catch (java.io.UnsupportedEncodingException e) { System.err.println(编码设置失败使用默认编码); } // ... 后续菜单循环 }验证方法在addEmployee()中输入“龘”字姓名观察printEmployee()输出是否正常。若仍乱码需在 IDE 运行配置中添加 VM 参数-Dfile.encodingUTF-8。5.2 将 ArrayList 持久化到文件简易版课程设计常要求数据不随程序退出丢失。以下代码将员工列表序列化为文本文件每行一条员工记录字段用|分隔private static final String DATA_FILE employees.txt; private static void saveToFile() { try (java.io.PrintWriter writer new java.io.PrintWriter( new java.io.FileWriter(DATA_FILE, false))) { for (Employee emp : employees) { writer.printf(%s|%s|%s|%d|%.2f|%s%n, emp.getId(), emp.getName(), emp.getPosition(), emp.getAge(), emp.getSalary(), emp.getDepartment()); } System.out.println( 数据已保存至 DATA_FILE); } catch (java.io.IOException e) { System.err.println(文件保存失败 e.getMessage()); } } private static void loadFromFile() { try (java.io.BufferedReader reader new java.io.BufferedReader( new java.io.FileReader(DATA_FILE))) { String line; while ((line reader.readLine()) ! null) { String[] parts line.split(\\|, -1); // -1 保留末尾空字段 if (parts.length 6) { try { Employee emp new Employee( parts[0], parts[1], parts[2], Integer.parseInt(parts[3]), Double.parseDouble(parts[4]), parts[5] ); employees.add(emp); } catch (NumberFormatException | IllegalArgumentException e) { System.err.println(跳过无效记录 line); } } } System.out.println( 从 DATA_FILE 加载 employees.size() 条员工数据); } catch (java.io.FileNotFoundException e) { System.out.println( 首次运行未找到数据文件 DATA_FILE 将创建新文件。); } catch (java.io.IOException e) { System.err.println(文件读取失败 e.getMessage()); } }使用时机在main()开头调用loadFromFile()在while循环结束前case 0分支内调用saveToFile()。文件格式兼容 Excel 导入字段顺序与Employee构造一致。5.3 用 Lambda 表达式重构查询逻辑提升可读性原findEmployeesByDepartment()使用传统 for 循环可改为 Stream API 链式调用语义更聚焦private static void findEmployeesByDepartment() { String dept getStringInput(请输入部门名称); ListEmployee result employees.stream() .filter(emp - dept.equalsIgnoreCase(emp.getDepartment())) .collect(java.util.stream.Collectors.toList()); if (result.isEmpty()) { System.out.println(⚠️ 部门 dept 下无员工。); } else { System.out.println(\n--- 部门 dept 员工列表 ---); result.forEach(EmpManager::printEmployee); } }优势对比filter()明确表达“筛选条件”collect()将结果聚合为新列表避免手动new ArrayList()和add()若后续需统计人数只需在链中追加.count()即可无需额外变量。控制台程序的价值不在界面华丽而在逻辑纯粹、路径透明、调试直观。当你能用ArrayList和Scanner把员工管理的每个环节拆解清楚Java 的面向对象根基才算真正立住。本文还有配套的精品资源点击获取
返回列表