JavaSE进阶——Day07 集合嵌套、Collections工具类、日志框架

JavaSE进阶——Day07 该篇主要讲解Java中的集合嵌套、Collections工具类、日志框架

Map集合:(双列集合)

回顾

  • 一次存储两个元素(key、value)
    • key不能重复、value可以重复
    • 一个key只能对应一个value
  • 不能直接遍历(间接性遍历)
    • 键找值:先获取Map集合中所有的key元素,遍历所有的key元素,在遍历过程中通过key找到value
    • 键值对:先获取Map集合中所有的键值对对象(Map.Entry),遍历所有的键值对对象,在遍历过程中获取到key和value

案例

使用Map集合统计字符串中每个字符出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package map.example;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/22 21:58
* @Project JavaCode_SE_Advance
* @Theme 使用Map集合统计字符串中每个字符出现的次数
*/
public class MapDemo1 {
//统计字符串中每个字符出现的次数
//"ethanliuloveqiu"
//a(1) q(1) t(1) e(2) u(2) v(1) h(1) i(2) l(2) n(1) o(1)

public static void main(String[] args) {
//字符串
String strs = "ethanliuloveqiu";

//统计字符次数
//初始化哈希表对象
Map<Character, Integer> recordMap = new HashMap<>();

//遍历字符串
for (int i = 0; i < strs.length(); i++) {
//取出对应字符
char strChar = strs.charAt(i); // String类的charAt()方法

//判断字符串是否存在
if (recordMap.containsKey(strChar)) {
//2.存在: 通过该字符的key找value, 对value + 1, 将结果重新写入对应的key和value (修改)
recordMap.put(strChar, recordMap.get(strChar) + 1);
} else {
//1.不存在: 将该字符作为key, 并初始化对应的value为1
recordMap.put(strChar, 1);
}
}

//System.out.println(recordMap);
//遍历Map集合设置输出格式 (Map遍历方式2)
Set<Map.Entry<Character, Integer>> entries = recordMap.entrySet(); //定义键值对对象的Set集合对象
for (Map.Entry<Character, Integer> entry : entries) { //增强for遍历键值对
char key = entry.getKey(); //单个键值对取键
int value = entry.getValue(); //单个键值对取值
System.out.print(key + "(" + value + ") ");
}
}
}

集合的嵌套

List嵌套List

  • 使用场景举例:一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,保存一个年级所有的班级信息

  • 思路:

    • 可以使用List集合保存一个班级的学生

    • 可以使用List集合保存所有班级

  • 因此我们可以定义集合如下:

    • 班级:List

      • 举例 :
                List<String> 一班 = {迪丽热巴 , 古力娜扎 ,马尔扎哈 ,欧阳娜娜}
                List<String> 二班 = {李小璐 , 白百何 , 马蓉}
                List<String> 三班 = {林丹 ,文章, 陈赫}
        
    • 年级:List>

      • 举例 :
                List<List<String>> 年级 = {一班 , 二班 , 三班}
        

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package nesting;

import java.util.ArrayList;
import java.util.List;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/23 08:48
* @Project JavaCode_SE_Advance
* @Theme List嵌套List集合
*/
public class ListNestListDemo {
public static void main(String[] args) {
//班级1
List<String> classes1 = new ArrayList<>();
classes1.add("迪丽热巴");
classes1.add("古力娜扎");
classes1.add("马尔扎哈");
classes1.add("欧阳娜娜");

//班级2
List<String> classes2 = new ArrayList<>();
classes2.add("李小璐");
classes2.add("白百何");
classes2.add("马蓉");

//班级3
List<String> classes3 = new ArrayList<>();
classes3.add("林丹");
classes3.add("文章");
classes3.add("陈赫");

//年级 (存储多个班级)
List<List<String>> grade = new ArrayList<>();
grade.add(classes1);
grade.add(classes2);
grade.add(classes3);

//遍历List嵌套集合
for (List<String> classes : grade) {
for (int i = 0; i < classes.size(); i++) {
System.out.println(classes.get(i));
}
System.out.println("-----------------");
}
}
}

List嵌套Map

/*
List嵌套Map :

使用场景举例:一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名有与之对应的学号,保存一年级所有的班级信息。

思路:
1 可以使用Map集合保存一个班级的学生(键是学号,值是名字)
2 可以使用List集合保存所有班级

因此我们可以定义集合如下:

班级:Map 键是学号,值是姓名
举例 :
Map 一班 = {it001 = 迪丽热巴 , it002 = 古力娜扎 ,it003 = 马尔扎哈 ,it004 = 欧阳娜娜}
Map 二班 = {it001 = 李小璐 , it002 = 白百何 , it003 = 马蓉}
Map 三班 = {it001 = 林丹 ,it002 = 文章, it003 = 陈赫}

年级:List>保存每个班级的信息
举例 :
List> 年级 = {一班 , 二班 , 三班}

*/

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package nesting;

import java.util.*;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/23 08:59
* @Project JavaCode_SE_Advance
* @Theme List嵌套Map
*/
public class ListNestMapDemo {
public static void main(String[] args) {
//班级1
Map<String, String> clases1 = new HashMap<>();
clases1.put("it001", "迪丽热巴");
clases1.put("it002", "古力娜扎");
clases1.put("it003", "马尔扎哈");
clases1.put("it004", "欧阳娜娜");
//班级2
Map<String, String> clases2 = new HashMap<>();
clases2.put("it001", "李小璐");
clases2.put("it002", "白百何");
clases2.put("it003", "马蓉");
//班级1
Map<String, String> clases3 = new HashMap<>();
clases3.put("it001", "林丹");
clases3.put("it002", "文章");
clases3.put("it003", "陈赫");

//在List集合中存储Map集合
List<Map<String, String>> grade = new ArrayList<>();
grade.add(clases1);
grade.add(clases2);
grade.add(clases3);

//遍历方式选择器
Scanner scanner = new Scanner(System.in);
System.out.print("请输入遍历方式(1或者2):");
String caseSelect = scanner.nextLine();

//遍历嵌套集合
for (Map<String, String> classes : grade) {

//Set<Map.Entry<String, String>> set = classes.entrySet();
if (caseSelect.equals("2")) {
//遍历班级(Map遍历方式2)
for (Map.Entry<String, String> stringStringEntry : classes.entrySet()) {
System.out.println(stringStringEntry.getKey() + ": " + stringStringEntry.getValue());
}

System.out.println("---------------");
}

if (caseSelect.equals("1")) {
//使用key找value遍历(遍历方式1)
for (String s : classes.keySet()) {
System.out.println(s + "---" + classes.get(s));
}
System.out.println("----------------");
}
}
}
}

Map嵌套Map

​ Map嵌套Map

  • 使用场景举例:一个年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名有与之对应的学号,保存一年级所有的班级信息,班级有与之对应的班级名称。

  • 思路:

    • 可以使用Map集合保存一个班级的学生(键是学号,值是名字)

    • 可以使用Map集合保存所有班级(键是班级名称,值是班级集合信息)

  • 因此我们可以定义集合如下:

    班级: Map<String,String> 键:学号,值:姓名

    举例 :
    Map<String,String> 一班 = {it001 = 迪丽热巴 , it002 = 古力娜扎,it003 = 马尔扎哈 ,it004 = 欧阳娜娜}

    Map<String,String> 二班 = {it001 = 李小璐 , it002 = 白百何 ,it003 = 马蓉}

    ` Map<String,String> 三班 = {it001 = 林丹, it002 = 文章, it003 = 陈赫}`
    

    年级: Map<String , Map<String,String>> 键:班级名称,值:具体班级信息

    举例:

        `Map<String, Map<String,String>> 年级 = {"一班" = 一班 , "二班" = 二班 , "三班" = 三班 }`
    

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package nesting;

import java.util.HashMap;
import java.util.Map;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/23 09:26
* @Project JavaCode_SE_Advance
* @Theme Map嵌套Map
*/
public class MapNestMapDemo {
public static void main(String[] args) {
//班级1 : 存储学号、姓名
Map<String, String> classes1 = new HashMap<>();
classes1.put("it001", "迪丽热巴");
classes1.put("it002", "古力娜扎");
classes1.put("it003", "马尔扎哈");
classes1.put("it004", "欧阳娜娜");
//班级2
Map<String, String> classes2 = new HashMap<>();
classes2.put("it001", "李小璐");
classes2.put("it002", "白百何");
classes2.put("it003", "马蓉");
//班级3
Map<String, String> classes3 = new HashMap<>();
classes3.put("it001", "林丹");
classes3.put("it002", "文章");
classes3.put("it003", "陈赫");

//Map集合中存储Map集合(把班级存储到年级下 , 给每个班级定个名字)
//注意创建的写法, 多练习几次
Map<String, Map<String, String>> grade = new HashMap<>();
grade.put("一班", classes1);
grade.put("二班", classes2);
grade.put("三班", classes3);

//遍历嵌套集合
//外层遍历(遍历班级)key ->> value遍历
for (String classnName : grade.keySet()) {
System.out.println(classnName + ":");
//内层遍历(遍历班级学生)
for (Map.Entry<String, String> stu : grade.get(classnName).entrySet()) {
System.out.println(stu.getKey() + "---" + stu.getValue());
}
System.out.println("-----------------------------");
}

}
}

嵌套集合梳理

  • 嵌套for循环:
1
2
3
4
5
6
7
for()
{
for()
{

}
}
  • 可以应用于:二维数组遍历、嵌套集合遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int[][] array = {  {1,2,3},  {4,5} };

    for(int i=0; i<array.length; i++)
    {
    //取出每一个元素(一维数组)
    int[] arr = array[i];
    //{1,2,3}
    // {4,5}

    for(int j=0; j<arr.length ;j++)
    {
    int num = arr[j];
    }
    }
    1
    2
    3
    4
    5
    6
    7
    list1[  list2[1,2,3] , list3[4,5]  ]

    //遍历:list1
    //取出每一个元素:list2、list3
    //遍历 : list2 、list3

    Map同理

Collections工具类

工具类

Arrays工具类:是针对数组提供了一些功能(排序、转换为字符串)

Collections工具类: 是针对集合提供了一些功能(排序、二分查询、乱序、添加另一个集合)

Collections工具类

1
2
//把给定的元素添加到指定的集合中
Collections.addAll( List或Set集合 , 元素1,元素2,...... );
1
2
3
Collections.sort( 集合 );//对集合中的元素进行排序(自然排序、比较器)

Collections.shuffle( 集合 );//对集合中的元素随机打乱顺序

斗地主案例

需求

按照斗地主的规则,完成洗牌发牌的动作。

  • 要求完成以下功能:

    1. 准备牌:组装54张扑克牌

    2. 洗牌:54张牌顺序打乱

    3. 发牌:三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。

    4. 看牌:查看三人各自手中的牌(按照牌的大小排序)、底牌

  • 规则:手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3

image-20240423230805585

逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package doudizhu;

import java.util.*;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/23 20:59
* @Project JavaCode_SE_Advance
* @Theme 斗地主案例
*/
public class Test1 {
public static void main(String[] args) {
//Map集合: 存储扑克牌的编号和牌面值
Map<Integer, String> pokerMap = new HashMap<>();
//List集合: 存储扑克牌编号(用于洗牌等)
List<Integer> pokerNumber = new ArrayList<>();
//TreeSet集合: 存储玩家信息和发牌情况(三个后面写)

//功能1: 准备牌
//"红星2" "黑桃2" "梅花2" "方片2" ......
String[] color = {"❤", "♠", "♣", "♦"}; //颜色形状
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};//数值

int count = 0; //牌数计数(或编号)
//合并牌
for (int i = 0; i < number.length; i++) {
for (int j = 0; j < color.length; j++) {
pokerMap.put(count, color[j].concat(number[i])); //合并牌
pokerNumber.add(count); //添加扑克牌编号
count++;
}
}
//添加大小王
if (count < 55) {
pokerMap.put(count, "小\uD83C\uDCCF");
pokerNumber.add(count);
count += 1;
pokerMap.put(count, "大\uD83C\uDCCF");
pokerNumber.add(count);
}

//功能2: 洗牌
Collections.shuffle(pokerNumber); //返回前面添加扑克牌编号
//System.out.println(pokerNumber);

//功能3: 发牌 发的是扑克牌编号并排序
TreeSet<Integer> player1 = new TreeSet<>();
TreeSet<Integer> player2 = new TreeSet<>();
TreeSet<Integer> player3 = new TreeSet<>();
TreeSet<Integer> dp = new TreeSet<>(); //底牌

for (int idx = 0; idx < pokerNumber.size(); idx++) {
//保留底牌
if (idx > 50) /*idx是从0开始的哦*/ {
dp.add(pokerNumber.get(idx));
continue;
}

if (idx % 3 == 0) /* 玩家1拿牌 */ {
player1.add(pokerNumber.get(idx));
} else if (idx % 3 == 1) /* 玩家2拿牌 */ {
player2.add(pokerNumber.get(idx));
} else /* 玩家3拿牌 */ {
player3.add(pokerNumber.get(idx));
}
}
System.out.println(player1.size());
System.out.println(player2.size());
System.out.println(player3.size());
System.out.println(dp);

//功能4: 看牌(方法定义)
lookPoker("Ethan", player1, pokerMap);
lookPoker("Qiu", player2, pokerMap);
lookPoker("BaoJie", player3, pokerMap);
lookPoker("底牌", dp, pokerMap);
}

/**
* //功能4: 看牌(方法定义)
*
* @param name 玩家名字
* @param player 玩家牌编号
* @param pokerMap 存储扑克牌的编号和牌面值
*/
public static void lookPoker(String name, TreeSet<Integer> player, Map<Integer, String> pokerMap) {
System.out.print(name + ": ");

//遍历玩家牌编号
for (Integer pokerNum : player) {
//根据编号获取牌的值
System.out.print(pokerMap.get(pokerNum) + " ");
}
System.out.println();
}
}

遇到问题

TreeSet集合自带自然排序的功能未掌握

image-20240423221400608

日志框架

日志技术的概述

  • 常见的日志规范:

Commons Logging

Simple Logging Facade for Java(slf4j)

  • 日志的实现框架:

    Log4J

    Logback(重点学习的,其他的都大同小异)

日志技术体系结构

Logback概述

image-20240424002912733

Logback快速入门

补充

使用java语言开发完成的程序,要给其他人使用,怎么办呢?

  • 把程序打包: xxxx.jar (jar文件是java文件压缩包)

要使用第三方开发好的程序,怎么办?

  • 在自己的项目工程下,导入xxx.jar包

使用Logback的步骤:

  1. 导入Logback所需的相关jar文件,并添加到项目资源库中
    • 在项目工程下新建lib文件夹,把logback需要的jar文件存放到该文件夹下
    • lib目录下的存储的jar文件,添加到当前项目资源库中
  2. 把logback核心配置文件,拷贝到当前项目的src目录下
  3. 在类中获取到Logger日志对象,使用日志对象中的API方法记录需要的操作信息

Logback日志框架的核心:logback.xml

  • xml文件

Logback配置详解-输出位置、格式设置

Logback配置详解-日志级别设置

(略)

Logback日志级别(从大到小):

  1. error //错误
  2. warn //警告
  3. info //信息
  4. debug //调试
  5. trace //追踪(例:追踪用户行为轨迹)