当前位置: 首页 > news >正文

Java结课案例-景点人数统计的几种场景

目录

案例要求:

实现思路:

代码:

总结:


案例要求:

第三题(20 分)
某班级要组织秋游活动,有四个景点的数据可以选择,依次是:“东湖”、“黄鹤楼”、“木兰文化区”、“归元禅寺”,每名学生最多可以选择两个想去的景点,最少要选择 1 个想去的景点,现在系统收集到了班级多名学生选择的信息如下。

plaintext
String info = "10001,张无忌,男,2023-07-22 11:11:12,东湖-黄鹤楼#10002,赵敏,女,2023-07-22 09:11:21,黄鹤楼-归元禅寺#10003,周芷若,女,2023-07-22 04:11:21,木兰文化区-东湖#10004,小昭,女,2023-07-22 08:11:21,东湖#10005,灭绝,女,2023-07-22 17:11:21,归元禅寺";

新建测试类,在类中书写 main 方法,在方法中完成如下业务逻辑:
业务一:
需要你解析上面的字符串,获取里面的用户数据,并封装到 Student 对象中
多个 Student 对象在添加到 List<Student> 集合中
注意:
字符串中的规则如下,多个用户用 # 拼接,用户的信息之间用 , 拼接;多个景点是用 - 拼接的。
其中用户的 id 和选择时间是需要进行类型转换的,其中 id 需要将 String 转成 Long,选择时间需要将 String 转成 LocalDateTime。
业务二:
遍历上面获取的 List<Student> 集合,统计里面每个景点选择的次数,并输出 景点名称和选择的次数。
业务三:
请用程序计算出哪个景点想去的人数最多,以及哪些人没有选择这个最多人想去的景点。

实现思路:

代码:

package com.itheima.demo3;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class test3 {public static void main(String[] args) {String info = "10001,张无忌,男,2023-07-22 11:11:12,东湖-黄鹤楼#10002,赵敏,女,2023-07-22 09:11:21,黄鹤楼-归元禅寺#10003,周芷若,女,2023-07-22 04:11:21,木兰文化区-东湖#10004,小昭,女,2023-07-22 08:11:21,东湖#10005,灭绝,女,2023-07-22 17:11:21,归元禅寺";String[] split = info.split("#");List<Student> list = new ArrayList<>();DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");for (String s : split) {String[] sin = s.split(",");Long id=Long.parseLong(sin[0]);String name = sin[1];String sex = sin[2];LocalDateTime birthday = LocalDateTime.parse(sin[3], dtf);String address = sin[4];Student student = new Student(id, name, sex, birthday, address);list.add(student);}Map<String,Integer> map=new HashMap<>();for(Student student:list){String[] address=student.getAddress().split("-");for(int i=0;i<address.length;i++){map.put(address[i],map.getOrDefault(address[i],0)+1);}}System.out.println("选择的景点及其去的人数展示:");for(Map.Entry<String,Integer> entry:map.entrySet()){String address=entry.getKey();int count=entry.getValue();System.out.println(address+":"+count);}//使用stream流解决哪个景点去的人数最多及其哪些人没有选择这个人数最多景点String mostPlace = map.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);System.out.println("投票最多的景点是:"+mostPlace);List<String> studentsWithoutMostPlace = list.stream().filter(student -> !student.getAddress().contains(mostPlace)).map(Student::getName).collect(Collectors.toList());System.out.println("没有选择投票最多去处的学生:"+studentsWithoutMostPlace);}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Student{private Long id;private String name;private String sex;private LocalDateTime birthday;private String address;
}

秋游景点选择统计程序代码深度解析
这段 Java 代码是一个针对 “班级秋游景点选择” 场景的完整解决方案,实现了从字符串解析到数据统计的全流程功能。代码基于面向对象思想和流式编程,清晰完成了题目要求的三个核心业务,以下从功能实现、代码结构、关键逻辑等方面展开详细解析。
一、整体功能与业务匹配度
程序严格按照题目要求,实现了三个核心业务:

业务一:解析原始字符串 info,提取学生信息并封装为 Student 对象,最终存入 List<Student> 集合;
业务二:统计每个景点的被选择次数,并输出统计结果;
业务三:找出最受欢迎的景点(选择人数最多的景点),并筛选出未选择该景点的学生名单。

代码逻辑链完整,从数据解析到统计分析层层递进,完全覆盖题目中的所有需求点,且通过 Lombok 注解和 Stream API 简化了代码实现。
二、核心组件与代码结构解析
1. 自定义 Student 类:数据封装的核心
java
运行
@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
    private Long id;               // 学生编号(Long类型)
    private String name;           // 学生姓名
    private String sex;            // 学生性别
    private LocalDateTime birthday;// 选择时间(LocalDateTime类型)
    private String address;        // 选择的景点(可能是1-2个,用-分隔)
}

属性设计:严格对应原始字符串中的数据字段,其中:
id 和 birthday 需进行类型转换(分别从 String 转 Long 和 LocalDateTime);
address 存储原始景点字符串(如 “东湖 - 黄鹤楼”),后续需进一步拆分统计。
Lombok 注解的作用:
@Data:自动生成 getter、setter、toString 等方法,避免重复代码;
@AllArgsConstructor 和 @NoArgsConstructor:自动生成全参和无参构造器,方便对象创建(尤其是解析字符串时直接通过全参构造器实例化)。
2. 业务一:字符串解析与对象封装
这部分是程序的数据输入层,负责将原始字符串转换为结构化的 Student 对象集合,核心代码如下:

java
运行
String info = "10001,张无忌,男,2023-07-22 11:11:12,东湖-黄鹤楼#10002,赵敏,女,2023-07-22 09:11:21,黄鹤楼-归元禅寺#10003,周芷若,女,2023-07-22 04:11:21,木兰文化区-东湖#10004,小昭,女,2023-07-22 08:11:21,东湖#10005,灭绝,女,2023-07-22 17:11:21,归元禅寺";
String[] split = info.split("#");  // 按#拆分多个学生信息
List<Student> list = new ArrayList<>();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");  // 时间格式化器

for (String s : split) {
    String[] sin = s.split(",");   // 按,拆分单个学生的字段
    Long id = Long.parseLong(sin[0]);  // String转Long(学生编号)
    String name = sin[1];
    String sex = sin[2];
    LocalDateTime birthday = LocalDateTime.parse(sin[3], dtf);  // String转LocalDateTime(选择时间)
    String address = sin[4];
    Student student = new Student(id, name, sex, birthday, address);  // 创建对象
    list.add(student);  // 加入集合
}
关键解析步骤:
字符串拆分逻辑:
先按 # 拆分原始字符串(info.split("#")),得到每个学生的完整信息字符串(如 "10001,张无忌,男,2023-07-22 11:11:12,东湖-黄鹤楼");
再对每个学生字符串按 , 拆分(s.split(",")),得到具体字段数组(如 ["10001", "张无忌", "男", "2023-07-22 11:11:12", "东湖-黄鹤楼"])。
类型转换处理:
id:通过 Long.parseLong(sin[0]) 将字符串编号转为 Long 类型,满足题目 “id 需要 String 转 Long” 的要求;
选择时间:通过 LocalDateTime.parse(sin[3], dtf) 转换,其中 DateTimeFormatter 按原始时间格式(yyyy-MM-dd HH:mm:ss)定义,确保转换正确。
对象封装与集合存储:
每个学生的字段通过 Student 全参构造器实例化为对象,最终存入 list 集合,完成从 “非结构化字符串” 到 “结构化对象集合” 的转换,为后续统计提供数据基础。
3. 业务二:景点选择次数统计
这部分通过 Map 集合统计每个景点的被选择次数,核心代码如下:

java
运行
Map<String, Integer> map = new HashMap<>();
for (Student student : list) {
    String[] address = student.getAddress().split("-");  // 拆分景点(1-2个)
    for (int i = 0; i < address.length; i++) {
        // 统计次数:若景点已存在则+1,否则初始化为1
        map.put(address[i], map.getOrDefault(address[i], 0) + 1);
    }
}

// 输出统计结果
System.out.println("选择的景点及其去的人数展示:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String address = entry.getKey();
    int count = entry.getValue();
    System.out.println(address + ":" + count);
}
统计逻辑解析:
景点拆分:对每个学生的 address 字段按 - 拆分(如 “东湖 - 黄鹤楼” 拆分为 ["东湖", "黄鹤楼"]),支持 1 个或 2 个景点的场景;
次数累加:使用 map.getOrDefault(address[i], 0) + 1 实现高效统计:
getOrDefault 方法在景点不存在时返回默认值 0,存在时返回当前计数;
每次累加后通过 map.put 更新计数,确保每个景点的选择次数准确。
结果输出:遍历 Map 的键值对(Map.Entry),打印每个景点及其对应的选择次数,满足题目 “输出景点名称和选择次数” 的要求。
4. 业务三:最受欢迎景点及未选择该景点的学生筛选
这部分利用 Stream API 实现高级统计,核心代码如下:

java
运行
// 找出选择次数最多的景点
String mostPlace = map.entrySet().stream()
        .max(Map.Entry.comparingByValue())  // 按值(次数)取最大值
        .map(Map.Entry::getKey)             // 提取最大值对应的键(景点名称)
        .orElse(null);                      // 无结果时返回null
System.out.println("投票最多的景点是:" + mostPlace);

// 筛选未选择该景点的学生姓名
List<String> studentsWithoutMostPlace = list.stream()
        .filter(student -> !student.getAddress().contains(mostPlace))  // 过滤条件:地址不包含最受欢迎景点
        .map(Student::getName)  // 提取学生姓名
        .collect(Collectors.toList());  // 收集为列表
System.out.println("没有选择投票最多去处的学生:" + studentsWithoutMostPlace);
核心逻辑解析:
最受欢迎景点筛选:
将 map 的键值对转换为流(map.entrySet().stream());
用 max(Map.Entry.comparingByValue()) 按值(选择次数)排序并取最大值,得到包含最多选择次数的 Map.Entry;
用 map(Map.Entry::getKey) 提取该条目对应的键(景点名称),完成 “找最多” 的需求。
未选择该景点的学生筛选:
将学生集合 list 转换为流(list.stream());
用 filter 方法保留满足条件的学生:!student.getAddress().contains(mostPlace)(地址字符串中不包含最受欢迎景点);
用 map(Student::getName) 提取这些学生的姓名;
用 collect(Collectors.toList()) 收集结果为列表,完成 “找未选择该景点的学生” 的需求。
三、代码设计亮点与技术细节
1. 分层处理的清晰逻辑
代码按 “数据解析→统计→分析” 的流程分层实现,每一步专注于单一职责:

业务一:只负责数据转换,将原始字符串转为可操作的对象集合;
业务二:只负责基础统计,计算每个景点的选择次数;
业务三:只负责高级分析,基于已有统计结果进一步挖掘信息。
这种分层设计使代码结构清晰,便于调试和维护。
2. 高效的字符串处理与类型转换
多级拆分:通过 split("#")→split(",")→split("-") 的多级拆分,精准提取嵌套在字符串中的字段,适配题目中 “# 分隔学生、, 分隔字段、- 分隔景点” 的格式规则;
安全的类型转换:使用 Long.parseLong 和 LocalDateTime.parse 进行类型转换,并通过预定义的 DateTimeFormatter 确保时间格式匹配,避免转换异常。
3. 集合与流式编程的灵活运用
Map 统计:用 HashMap 存储景点次数,getOrDefault 方法简化了 “存在则累加,不存在则初始化” 的逻辑,比传统 if-else 更简洁;
Stream API 优化:业务三中的两个核心需求均通过流式编程实现,避免了传统的 for 循环和 if 判断,代码更简洁且可读性更高:
max(Map.Entry.comparingByValue()) 替代了 “遍历找最大值” 的循环;
filter+map 替代了 “遍历筛选 + 提取姓名” 的循环。
4. 面向对象的封装优势
通过 Student 类封装学生信息,将分散的字段整合为对象,避免了使用多个数组或变量存储数据的混乱,同时通过 getter 方法(Lombok 自动生成)方便后续流式编程中提取属性(如 Student::getName)。
四、示例执行结果与流程验证
以题目中的 info 字符串为例,程序执行流程与结果如下:

业务一解析后:list 集合包含 5 个 Student 对象,对应 5 名学生的信息;
业务二统计结果:
东湖:3 次(张无忌、周芷若、小昭)
黄鹤楼:2 次(张无忌、赵敏)
归元禅寺:2 次(赵敏、灭绝)
木兰文化区:1 次(周芷若)
输出为:
plaintext
选择的景点及其去的人数展示:
东湖:3
黄鹤楼:2
归元禅寺:2
木兰文化区:1

业务三分析结果:
最受欢迎景点为 “东湖”(3 次);
未选择东湖的学生为赵敏、灭绝;
输出为:
plaintext
投票最多的景点是:东湖
没有选择投票最多去处的学生:[赵敏, 灭绝]

五、可优化点与拓展思考
异常处理增强:当前代码未处理可能的异常(如字符串格式错误、类型转换失败),可添加 try-catch 块增强健壮性,例如:
java
运行
try {
    Long id = Long.parseLong(sin[0]);
    LocalDateTime birthday = LocalDateTime.parse(sin[3], dtf);
} catch (NumberFormatException | DateTimeParseException e) {
    System.out.println("数据格式错误:" + e.getMessage());
}

景点去重校验:题目说明 “每名学生最多选择两个景点”,当前代码未校验是否有重复景点(如 “东湖 - 东湖”),可在拆分后添加去重逻辑:
java
运行
String[] address = student.getAddress().split("-");
Set<String> uniqueAddresses = new HashSet<>(Arrays.asList(address));  // 去重
for (String addr : uniqueAddresses) { ... }

多景点并列最多的处理:当前代码用 max 只返回一个最多景点,若存在并列最多(如两个景点均为 3 次),可修改为返回所有并列景点:
java
运行
int maxCount = map.values().stream().max(Integer::compare).orElse(0);
List<String> mostPlaces = map.entrySet().stream()
        .filter(entry -> entry.getValue() == maxCount)
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());


总结
这段代码是 “字符串解析 + 数据统计” 类问题的典型实践,通过面向对象封装、集合操作和流式编程的结合,高效完成了题目要求的三个业务。其亮点在于逻辑分层清晰、代码简洁高效,充分利用了 Java 8+ 的新特性(如 Stream API、方法引用)简化实现。理解这段代码不仅能掌握字符串处理、类型转换、集合统计等基础技能,更能体会流式编程在数据处理中的优雅与高效,为处理类似 “解析 - 统计 - 分析” 的业务场景提供了参考范式。

总结:


本文详细解析了一个班级秋游景点选择统计的Java程序。该程序通过字符串解析将学生选择数据封装为Student对象,使用Map统计各景点选择次数,并利用Stream API找出最受欢迎景点及未选择该景点的学生名单。代码采用分层设计,结合面向对象思想和流式编程,实现了数据转换、基础统计和高级分析的全流程功能。程序亮点包括高效的字符串处理、安全的类型转换、集合与流式编程的灵活运用,以及使用Lombok简化代码。文章还提出了异常处理增强、景点去重校验等优化建议,为类似数据处理场景提供了参考范式。

http://www.dtcms.com/a/327585.html

相关文章:

  • 日期格式化成英文月,必須指定語言環境
  • Secure CRT做代理转发
  • HTTP应用层协议-长连接
  • 记对外国某服务器的内网渗透
  • C++少儿编程(二十二)—条件结构
  • 机械臂运动规划与控制12讲
  • SQL 语言分类
  • 后端学习路线
  • 3D文档控件Aspose.3D实用教程:在 C# 中将 3MF 文件转换为 STL
  • 开疆智能Ethernet转ModbusTCP网关连接发那科机器人与三菱PLC配置案例
  • Spring Boot部署万亿参数模型推理方案(深度解析)
  • css之再谈浮动定位float(深入理解篇)
  • 物联网、大数据与云计算持续发展,楼宇自控系统应用日益广泛
  • 黑马程序员mysql课程p65 安装linux版本的mysql遇到问题
  • [密码学实战]基于国密TLCP协议的Java服务端实现详解(四十四)
  • 【基于DesignStart的M3 SoC】
  • 4/5G中频段频谱全球使用现状概述(截止2025 年7月)
  • 【unity实战】在 Unity 中实现卡牌翻转或者翻书的效果
  • 现代化水库运行管理矩阵建设的要点
  • 学习笔记《区块链技术与应用》ETH 第二天 状态树
  • 解决 HTTP 请求 RequestBody 只能被读取一次的问题
  • 敏捷开发的关键点是什么?深入探索!
  • Windows server服务器上部署python项目域名访问(超详细教程)
  • Vue 3 + Elementui + TypeScript 实现左侧菜单定位右侧内容
  • 【实时Linux实战系列】实时智能监控与异常检测
  • 什么是 DispatcherServlet?
  • 【Java项目与数据库、Maven的关系详解】
  • 部署一个开源的证件照系统
  • Notepad++ 插件开发实战技术
  • 3.8 vue2 devServer配置和 CDN 加载外部资源