集合进阶-双列集合(十三)


集合进阶-双列集合(十三)

双列集合特点

  1. 双列集合一次需存储一对数据,分别为
  2. 不能重复,可以重复
  3. 是一一对应的,每个键只能找到自己对应的值
  4. 这个整体称之为键值对键值对对象,在Java中叫做Entry对象

Map

Map是双列集合的顶层接口,它的功能是全部双列集合都可继承使用的。

体系结构

  • Map(接口)
    • HashMap (实现类)->LinkedHashMap(实现类)
    • Hashtable(实现类)->Properties(实现类)
    • TreeMap(实现类)

常用方法

put

格式

V put(K key,V value)

说明:添加元素。

  • 在添加数据时,若键不存在,直接把键值对对象添加到map集合当中,方法返回是null
  • 在添加数据时,若键存在,会把原有的键值对对象覆盖,并将被覆盖的值进行返回。

remove

格式

V remove(Object Key)

说明:根据键删除键值对元素

clear

格式

void clear()

说明:移除所有键值对元素

containsKey

格式

boolean containsKey

说明:判断集合是否包含指定的键

containsValue

格式

boolean containsValue

说明:判断集合是否包含指定的值

isEmpty

格式

boolean isEmpty()

说明:判断集合是否为空

size

格式

int size()

说明:集合的长度,也是集合中键值对的个数

范例

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
import java.util.HashMap;
import java.util.Map;

public class Test {
public static void main(String[] args) {
Map<String,String> m=new HashMap<>();
System.out.println("put方法");
m.put("aaa","AAA");
m.put("bbb","BBB");
m.put("ccc","CCC");
System.out.println(m);
String value1=m.put("aaa","sss");
System.out.println(m);
System.out.println(value1);
String value2=m.put("ddd","DDD");
System.out.println(value2);
System.out.println(m);

System.out.println("\nremove方法");
m.remove("bbb");
System.out.println(m);

System.out.println("\ncontainsKey方法");
System.out.println(m.containsKey("aaa"));
System.out.println(m.containsKey("bbb"));


System.out.println("\ncontainsValue方法");
System.out.println(m.containsValue("DDD"));
System.out.println(m.containsValue("AAA"));


System.out.println("\nsize方法");
System.out.println(m.size());

System.out.println("\nisEmpty方法");
System.out.println(m.isEmpty());

System.out.println("\nclear方法");
m.clear();
System.out.println(m.isEmpty());
System.out.println(m);
}
}

遍历方式

  1. 键找值
  2. 键值对
  3. Lambda表达式

键找值

利用keySet方法将所有键放入一个单列集合中,遍历得到每一个键,通过get方法得到每个键对应的值。

keySet方法

Set keySet()

get方法

V get(Object key)

范例

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
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Map<String,String> m=new HashMap<>();
m.put("aaa","AAA");
m.put("bbb","BBB");
m.put("ccc","CCC");

Set<String> set=m.keySet();
System.out.println("迭代器遍历");
Iterator<String> it=set.iterator();
while(it.hasNext()){
String str=it.next();
System.out.println(str+" = "+m.get(str));
}

System.out.println("\n增强for");
for(String str:set){
System.out.println(str+" = "+m.get(str));
}

System.out.println("\nlambda");
set.forEach(str-> System.out.println(str+" = "+m.get(str)));
}
}
/*
迭代器遍历
aaa = AAA
ccc = CCC
bbb = BBB

增强for
aaa = AAA
ccc = CCC
bbb = BBB

lambda
aaa = AAA
ccc = CCC
bbb = BBB
*/

键值对

通过entrySet方法获取所有键值对对象,在通过键值对对象调用getkeygetValue获取键和值。

entrySet方法

Set<Map.Entry<K,V>> entrySet()

getkey方法

K getKey()

getValue方法:

V getValue()

范例

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
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Map<String,Integer> map=new HashMap<>();
map.put("a",97);
map.put("b",98);
map.put("c",99);
Set<Map.Entry<String,Integer>> entries=map.entrySet();
//若导入import java.util.Map.Entry;
//则可以直接Set<Entry<String,Integer>> entries=map.entrySet();
System.out.println("迭代器");
Iterator<Map.Entry<String,Integer>> it=entries.iterator();
while(it.hasNext()){
Map.Entry<String,Integer> entry=it.next();
String key=entry.getKey();
int value=entry.getValue();
System.out.println(key+" = "+value);
}

System.out.println("\nfor增强");
for(Map.Entry<String,Integer> entry:entries){
String key=entry.getKey();
int value=entry.getValue();
System.out.println(key+" = "+value);
}

System.out.println("\nLambda");
entries.forEach(entry-> System.out.println(entry.getKey()+" = "+entry.getValue()));
}
}
/*
迭代器
a = 97
b = 98
c = 99

for增强
a = 97
b = 98
c = 99

Lambda
a = 97
b = 98
c = 99
*/

Lambda表达式

方法名称

default void forEach(BiConsumer<? super K, ? super V> action)

说明:结合Lambda遍历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
import java.util.HashMap;
import java.util.Map;
//import java.util.function.BiConsumer;
public class Test{
public static void main(String[] args){
Map<String,Integer> map=new HashMap<>();
map.put("a",97);
map.put("b",98);
map.put("c",99);
/*
map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println(s+" = "+integer);
}
});
*/
map.forEach((s,integer)-> System.out.println(s+" = "+integer));
}
}
/*
a = 97
b = 98
c = 99
*/

选择方式

默认:HashMap(效率最高)

若要保证存取有序,LinkedHashMap

若要进行排序:TreeMap

HashMap

  1. HashMap是Map里的一个实现类,并无额外需要学习的特殊方法,直接使用Map的方法即可
  2. 特点是由键决定:无序,不重复,无索引
  3. HashMap和HashSet底层原理一样,都是哈希表结构
  4. 依赖hashCode和equals方法保证键的唯一
  5. 若键存储的是自定义对象,需重写hashCode和equals方法;若值存储的是自定义对象,不需重写hashCode和equals方法。

范例一

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)
存储三个键值对元素,并遍历。
要求:同姓名,同年龄认为是同一个学生
*/
//Student.java
import java.util.Objects;

public class Student{
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
//Test.java
import java.util.HashMap;
import java.util.Set;
public class Test {
public static void main(String[] args) {
HashMap<Student,String> hm=new HashMap<>();
Student stu1=new Student("zs",18);
Student stu2=new Student("lisi",19);
Student stu3=new Student("zs",18);
String s1="河北";
String s2="河南";
String s3="北京";
hm.put(stu1,s1);
hm.put(stu2,s2);
hm.put(stu3,s3);

System.out.println("lambda");
hm.forEach((stu,s)-> System.out.println(stu+" = "+ s));

System.out.println("键找值");
Set<Student> set=hm.keySet();
for(Student stu:set){
System.out.println(stu +" = "+hm.get(stu));
}
System.out.println("键值对");
Set<HashMap.Entry<Student,String>> entries=hm.entrySet();
for(HashMap.Entry<Student,String> entry:entries){
System.out.println(entry.getKey()+ " = "+entry.getValue());
}
}
}
/*
lambda
Student{name = lisi, age = 19} = 河南
Student{name = zs, age = 18} = 北京
键找值
Student{name = lisi, age = 19} = 河南
Student{name = zs, age = 18} = 北京
键值对
Student{name = lisi, age = 19} = 河南
Student{name = zs, age = 18} = 北京
*/

范例二:

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
/*
某个班级80个学生,现需组成春游活动
班长提供四个景区A,B,C,D
每个学生只能选择一个景区,并统计出哪个景区想去的人数最多
*/
package com.ljsblog.domain1;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Set;

public class Test {
public static void main(String[] args) {
String[] arr={"A","B","C","D"};
ArrayList<String> list=new ArrayList<>();
Random random=new Random();
for(int i=0;i<80;i++){
int index=random.nextInt(arr.length);
list.add(arr[index]);
}
HashMap<String,Integer> hm=new HashMap<>();
for(String name:list){
if(hm.containsKey(name)){
int c=hm.get(name);
c++;
hm.put(name,c);
}else{
hm.put(name,1);
}
}
Set<HashMap.Entry<String,Integer>> entries=hm.entrySet();
int max=0;
for(HashMap.Entry<String,Integer> entry:entries){
int value=entry.getValue();
if(max<value){
max=value;
}
}
System.out.println(hm);
System.out.println("最大为"+max);
for(HashMap.Entry<String,Integer> entry:entries){
if(max==entry.getValue()){
System.out.println(entry.getKey());
}
}

}
}
/*
{A=19, B=18, C=21, D=22}
最大为22
D
*/

LinkedHashMap

由键决定:有序不重复无索引

底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存取的顺序。

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.LinkedHashMap;
public class Test {
public static void main(String[] args) {
LinkedHashMap<String ,Integer> lhm=new LinkedHashMap<>();
lhm.put("a",96);
lhm.put("a",97);
lhm.put("b",98);
lhm.put("c",99);
System.out.println(lhm);
}
}
/*
{a=97, b=98, c=99}
*/

TreeMap

TreeMap跟TreeSet底层原理一样,都是红黑树结构的。

由键决定特性:不重复,无索引,可排序。

可排序:对键进行排序、

:默认按照键的从小到大进行排序,也可自己规定键的排序规则

代码书写的两种排序规则

  1. 实现Comparable接口,指定比较规则。
  2. 创建集合时传递Comparator比较器对象,指定比较规则

范例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
键:整数表示id
值:字符串表示商品名称
要求:按照id的升序排序,按照id的降序排序
*/

import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
//默认升序
TreeMap<Integer,String> tm1=new TreeMap<>();
tm1.put(6,"足球");
tm1.put(5,"篮球");
tm1.put(10,"橄榄球");
System.out.println(tm1);

//降序
TreeMap<Integer,String> tm2=new TreeMap<>((o1, o2)->o2-o1);
tm2.put(7,"足球");
tm2.put(6,"篮球");
tm2.put(10,"橄榄球");
System.out.println(tm2);
}
}

范例二

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
/*
键:学生对象(姓名和年龄)
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排序,同姓名通年龄视为同一人
*/
//Student.java
public class Student implements Comparable<Student>{
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}

@Override
public int compareTo(Student o) {
int i=this.getAge()-o.getAge();
return i==0?this.getName().compareTo(o.getName()):i;
}
}
//Test.java
import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
TreeMap<Student,String> tm=new TreeMap<>();
Student s1=new Student("zs",19);
Student s2=new Student("ww",18);
Student s3=new Student("zs",19);
Student s4=new Student("ls",19);
tm.put(s1,"河北");
tm.put(s2,"河南");
tm.put(s3,"湖南");
tm.put(s4,"湖北");
System.out.println(tm);
}
}

范例三

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
/*
统计字符串"aababcabcdabcde"每个字符出现的次数,并按以下格式输出:
a(5)b(4)c(3)d(2)e(1)
*/
import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
String str="aababcabcdabcde";
TreeMap<Character,Integer> tm=new TreeMap<>();
for(int i=0;i<str.length();i++){
Character c=str.charAt(i);
if(tm.containsKey(c)){
int count=tm.get(c);
count++;
tm.put(c,count);
}else {
tm.put(c,1);
}
}
StringBuilder sb=new StringBuilder();
tm.forEach((character, integer)->sb.append(character).append("(").append(integer).append(")"));
System.out.println(sb);
}
}
/*
a(5)b(4)c(3)d(2)e(1)
*/

可变参数

可变参数本质上是一个数组。

作用:在形参中接收多个数据。

格式

数据类型…参数名称

注意事项

  • 形参列表中可变参数只有一个

  • 可变参数必须放在形参列表的最后面

范例

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
public class Test {
public static void main(String[] args) {
System.out.println(sum(1, 2, 3, 4));
System.out.println(sum(1, 2, 3, 4, 5));
System.out.println("大于7的数字有"+compare(7, 11, 9, 4, 6, 7)+"个");
}
public static int sum(int...args){
int s=0;
for (int num:args){
s+=num;
}
return s;
}
public static int compare(int num,int...args){
int c=0;
for(int i=0;i<args.length;i++){
if(args[i]>num){
c++;
}
}
return c;
}
}
/*
10
15
大于7的数字有2个
*/

Collections

java.util.Collections是集合工具类。

作用:Collections不是集合,而是集合的工具类

常用方法

addAll

格式

public static boolean addAll(Collection c,T…elements)

说明

批量添加元素

shuffle

格式

public static void shuffle(List<?> list)

说明

打乱List集合元素的顺序

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
System.out.println("addAll方法");
Collections.addAll(list, "saf","fasf","df","fsa");
System.out.println(list+"\n");

System.out.println("shuffle方法");
Collections.shuffle(list);
System.out.println(list);
}
}
/*
addAll方法
[saf, fasf, df, fsa]

shuffle方法
[saf, df, fsa, fasf]
*/

范例

例1

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
/*
班级里有一些学生。
要求:被点到的学生不会再被点到。
若班级中所有学生点完,则开始下一轮点名
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Scanner;

public class Test {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
Collections.addAll(list,"张三","李四","王五","甲","乙","丙","丁");
ArrayList<String> list1=new ArrayList<>();
int i=1;
Scanner s=new Scanner(System.in);
Random r=new Random();
while(true){
System.out.print("若想退出输入0,非零继续循环,请输入:");
String in=s.nextLine();
if(in.compareTo("0")==0){
break;
}
System.out.println("第"+i+"轮点名");
list1.addAll(list);
while(list1.size()!=0){
int num=r.nextInt(list1.size());
System.out.println(list1.get(num));
list1.remove(num);
}
list1.clear();
i++;
}
}
}

例2

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
/*
定义一个map集合,键用表示省份名称province,值表示市city,但是市有多个,添加完毕后,遍历结果格式如下:
江苏省=南京市,扬州市,苏州市
湖北省=武汉市,孝感市,宜昌市
河北省=唐山市,邢台市,廊坊市
*/
import java.util.*;
public class Test {
public static void main(String[] args) {
ArrayList<String> city1=new ArrayList<>();
city1.add("南京市");
city1.add("扬州市");
city1.add("苏州市");

ArrayList<String> city2=new ArrayList<>();
city2.add("武汉市");
city2.add("孝感市");
city2.add("宜昌市");

ArrayList<String> city3=new ArrayList<>();
city3.add("唐山市");
city3.add("邢台市");
city3.add("廊坊市");

HashMap<String,ArrayList<String>> m=new HashMap<>();
m.put("江苏省",city1);
m.put("湖北省",city2);
m.put("河北省",city3);

Set<Map.Entry<String,ArrayList<String>>> entries=m.entrySet();
for(Map.Entry<String,ArrayList<String>> entry:entries){
StringJoiner sj=new StringJoiner(",");
ArrayList<String> value = entry.getValue();
for(String s:value){
sj.add(s);
}
System.out.println(entry.getKey()+"="+sj);
}
}
}
/*
江苏省=南京市,扬州市,苏州市
湖北省=武汉市,孝感市,宜昌市
河北省=唐山市,邢台市,廊坊市
*/

不可变集合

不可变集合:集合不可变,不能添加,修改,删除。

格式

在List,Set,Map接口中,均存在静态of方法,可获得一个不可变的集合。

  • 方法:static List of(E…element)
    • 创建一个具有指定元素的List集合对象
  • 方法:static Set of(E…element)
    • 创建一个具有指定元素的set集合对象,元素不能重复
  • 方法:static <K,V> Map<K,V> of(E…element)
    • 创建一个具有指定元素的Map集合对象,元素不能重复,键值对数量最多10个,超过10个用ofEntries方法

Properties

properties是一个双列集合,拥有Map集合的所有特点,本身也有一些特有方法,可把集合的数据按照键值对的形式写到配置文件(后缀.properties)当中,也可把配置文件中的数据,读取到集合中。

propertise集合没有泛型,可以添加任意类型数据,但一般添加字符串类型数据。

常用方法

store

格式1

public void store(Writer writer,String comments)

格式2

public void store(OutputStream out,String comments)

说明:把集合中的数据以键值对的形式写入到文件中,第二个参数为写入的注释

load

格式1

public void load(Reader reader)

格式2

public void load(InputStream inStream)

说明:读取本地文件里的数据。

范例

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
import java.io.*;
import java.util.Properties;

public class Test {
public static void main(String[] args) throws IOException {
Properties p1=new Properties();
p1.put("user","zhangsan");
p1.put("password","123456");
BufferedWriter bw=new BufferedWriter(new FileWriter("a.properties"));
p1.store(bw,"用户和密码");
bw.close();

Properties p2=new Properties();
BufferedReader br=new BufferedReader(new FileReader("a.properties"));
p2.load(br);
System.out.println(p2);
}
}
/*a.properties内容
#用户和密码
#Tue Apr 04 17:00:17 CST 2023
password=123456
user=zhangsan

*/

/*打印内容
{password=123456, user=zhangsan}
*/

Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC