今日内容
零、 复习昨日
一、集合框架体系
二、Collection
三、泛型
四、迭代
五、List(ArrayList、LinkedList)
零、 复习昨日
日期解析的方法签名(字符串–>日期)
- Date parse(String s)
日期格式化的方法签名(日期–>字符串)
- String format(Date date)
运行时异常有哪些,什么特点
- RuntimeException及其子类,编码时不用强制处理
编译期异常有哪些,什么特点
- 除了以上的都是,编码时必须强制处理
异常的处理方式哪些,什么区别
- 抛出,抛出后代码不再执行
- 捕获,捕获后还可以执行
finally干什么的
- 释放资源
throw和throws什么区别
- 位置?throw在方法内,throws在方法参数列表()后
- 后面写?throw后跟1个异常对象,throws后面跟多个异常类名
- 作用?throw是抛出异常对象的,throws只是声明可能要抛出异常类型
一、集合框架体系
数组: 存储多个数据的容器
- 数组长度固定
- 数组只能存储同一种类型
- 数组用法单一,只能通过下标取值赋值
- 数组内元素可以重复
- 数组内元素有顺序(存值时顺序)
集合(Collection): 存储多个数据的容器
- 集合长度不固定
- 集合可以存储不同类型
- 集合是一些列的类,可以创建对象,有丰富的方法可以操作数据
- 有些集合可以重复(List),有些集合不允许重复(Set);有些集合有序的(List),有些集合是无序的(HashSet),而且有些集合还会排序(TreeSet)
-
Collection是集合层次的父接口,定义了所有集合共性操作
-
Collection有两个常用子接口:List,Set
-
List接口集合,主要特征是有序,允许重复元素的集合
-
Set接口集合,主要特征是元素去重
-
List接口有两个常用实现类
- ArrayList,底层是数组,也是允许元素重复,数据有序
- LinkedList,底层是链表,也是允许元素重复,数据有序
-
Set接口有两个常用实现类
- HashSet,底层是hash表,存储的元素无序且去重
- TreeSet,底层是二叉树,存储的元素是排序且去重
二、Collection、List介绍
-
Collection父接口
- 定义了一部分集合的共性操作,并不全
-
List是Collection的子接口,有序允许重复的集合
- 定义了一些方法,可以对位置进行精准控制
- 即可以按照下标插入,删除,查询,修改集合元素
-
List是接口,不能只能直接用,常用使其子实现类,ArrayList和LinkedList
三、List
3.1、ArrayList[重点]
- 是List接口的实现类,允许重复,有序
- 底层是数组,大小"可变"
- 是不同步,即不保证线程安全
3.1.1 方法演示1
先演示了部分方法,主要对集合元素
增 删 改 查
public static void main(String[] args) {
// 创建空集合
ArrayList list = new ArrayList( );
System.out.println("初始值: " + list);
// 向末尾添加元素
// 有序(插入顺序),允许重复,允许存储不同类型
list.add(4);
list.add(2);
list.add(2);
list.add(5);
list.add("六");
System.out.println("添加值:" + list);
// 向指定下标插入数据
list.add(2, 1);
System.out.println("中间插入:" + list);
// 获得指定下标的元素
Object o = list.get(2);
System.out.println(o);
// 按照下标修改元素
list.set(2, 100);
System.out.println("修改后:" + list);
// 按下下标删除元素
Object old = list.remove(0);
System.out.println("被删除掉的元素:" + old );
System.out.println("删除后的集合:"+list );
}
3.1.2 泛型
private static void show2() {
/**
* 集合确实可以允许存储不同类型数据
* 但是大部分情况下,集合只会存储同一类型
* -----------
* 目前这种情况,设计时存储的是Object
* 取出数据也是Object,需要使用对应数据类型时需要强转
* 但是强制转换有风险
* ---------------------
* 所以,在JDK1.5时引入泛型 ,通过泛型就可以解决这个问题
*/
ArrayList list = new ArrayList( );
list.add(1);
list.add(2.0);
list.add("3");
list.add(new Date( ));
double o = (double) list.get(0);
System.out.println(o );
System.out.println("-------------------------" );
/**
* 下面使用泛型来定义集合
* 通过在类名后,指定泛型类型,从而确定该集合只能存储指定类型
* -------------
* 泛型好处: 减少类型转换(强转)
*/
ArrayList<Integer> list2 = new ArrayList<>( );
list2.add(1);// 有了泛型约束,存储时只能是Integer
list2.add(2);
list2.add(3);
Integer i = list2.get(2);// 有了泛型约束,取出就是Integer,无需强转
}
以后,凡是用集合操作,必用泛型!!
3.1.3 方法演示2
/**
* 演示ArrayList其他方法
*/
private static void show3() {
ArrayList<Integer> l1 = new ArrayList<>( );
l1.add(11);
l1.add(22);
l1.add(33);
System.out.println("原始l1:" + l1 );
ArrayList<Integer> l2 = new ArrayList<>( );
l2.add(10);
l2.add(20);
l2.add(30);
// 将另外一个集合中的全部元素加入当前集合
l1.addAll(l2);
System.out.println("addAll后: " + l1);
// 移除当前集合中,存在于参数集合相同的元素
l1.removeAll(l2);
System.out.println("移除后:" + l1 );
// 判断集合是否为空
System.out.println(l1.isEmpty( ));
// 存储的元素的个数
int size = l1.size( );
System.out.println("集合元素个数:" + size );
// 判断集合是否包含某个元素
System.out.println(l1.contains(11));
// 先创建整型数组
Integer[] integers = new Integer[l1.size( )];
// 再将集合转成数组
Integer[] array = l1.toArray(integers);
System.out.println(Arrays.toString(array));
// 清空集合
l1.clear();
System.out.println("清空后: " + l1 );
// 判断集合是否为空
System.out.println(l1.isEmpty( ));
}
3.1.4 迭代
集合遍历
// 使用迭代器遍历
public static void main(String[] args) {
/**
* 使用迭代器遍历
*/
ArrayList<Integer> list = new ArrayList<>( );
list.add(4);
list.add(2);
list.add(1);
list.add(3);
// 1)获得迭代器
Iterator<Integer> iterator = list.iterator();
// 2)遍历迭代
while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
Integer next = iterator.next( );// 取出下一个元素
System.out.println(next );
}
}
// foreach迭代
public static void main(String[] args) {
/**
* 使用迭代器遍历
*/
ArrayList<Integer> list = new ArrayList<>( );
list.add(4);
list.add(2);
list.add(1);
list.add(3);
// 1)获得迭代器
Iterator<Integer> iterator = list.iterator();
// 2)遍历迭代
while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
Integer next = iterator.next( );// 取出下一个元素
System.out.println(next );
}
// 迭代器的简化写法: 增强for循环,也叫foreach
/**
* for(数据类型 变量 : 集合) {
*
* }
*/
for (Integer i : list) {
System.out.println(i );
}
// 遍历数组
int[] arr = {1,2,3,4};
for(int i:arr){ // 冒号左边是遍历得到的结果,不是下标!!!
System.out.println(i);
}
}
3.1.5 底层原理[面试]
- ArrayList底层是数组实现的
- 起始容量(数组长度)默认是10
- 刚new完创建的空集合的,容量是0
- 当第一次加入元素的时候,数组扩容成10
- 当元素放满10个时,当加入第11个时候会触发扩容,扩容为原来的1.5倍(通过 >> 1 右移1位算出来)
- 扩容成1.5倍后,再把原数组的元素拷贝到新数组
// 扩容的源码 (ArrayList.java(
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
这个函数是用于增长数组容量的。当数组容量不足时,它将根据最小需求容量(minCapacity)来计算新的容量大小,并确保新的容量大于当前需求。若新容量小于需求,则将新容量设置为需求容量。若新容量超过最大数组大小,则调用hugeCapacity方法来处理。最后,通过Arrays.copyOf方法复制原数组到新的容量中。
使用上效率问题
- ArrayList进行元素的 查询,修改速度快
- 进行元素的,插入和删除速度慢
原因
- 数组在内存是连续空间,有下标
- 所以,通过下标直接定位找到元素,改变该位置元素(查询和更新快)
- 也是因为内存空间原因,插入或者删除一个数据时,从插入/删除位置开始后续的元素需要后移/前移一位
3.2、LinkedList[理解]
LinkedList也是List实现类,也是允许元素重复,有序集合
3.2.1 方法演示
LinkedList也是List实现类,大部分方法与ArrayList一模一样用法
- 创建LinkedList集合
- 加入元素
- foreach变量LinkedList
3.2.2 特殊方法
除了基本的方法与ArrayList一样之外,LinkedList还提供一些比较特殊的操作头尾的方法
- getFirst getLast
- removeFirst removeLast
- addFirst addLast
public static void main(String[] args) {
LinkedList<Integer> l1 = new LinkedList<>( );
l1.add(11);
l1.add(22);
l1.add(33);
// 获得头 尾操作
Integer first = l1.getFirst( );
Integer last = l1.getLast( );
System.out.println(first );
System.out.println(last );
}
3.2.3 底层原理
LinkedList底层是双向链表
- 链表在内存中是不连续
- 通过链域里面记录上一个/下一个元素的位置
当通过下标找寻一个元素的时候,并不是直接定位的,是从头或者尾开始一个一个遍历查找对应的元素,也正是因为如此,所以提供了专门操作头尾的方法的,可以直接定位到,方便操作
又因为这个空间数据结构问题,导致了一些特性
- LinkedList查询,更新数据慢
- LinkedList插入,删除的快
- 因为插入/删除元素改变的知识链域的记录信息,没有改变其他元素位置
四、Set
- Set是Collection的子接口
- 规定所存储的元素是不允许重复,且无序
- HashSet的无序是将存储的元素随机排序
- TreeSet的"无序" 是指将存储的元素给排序了
- Set接口一般常用两个实现类
- HashSet,存储的元素是无序且去重
- TreeSet,存储的元素是去重且排序
4.1、HashSet
是Set接口的实现类,存储的元素是无序且去重,不保证线程安全
4.1.1 方法演示
HashSet() 空参构造,创建空集合
HashSet(Collection c) 创建带有元素的集合
方法都是常规方法,没有关于下标的操作
private static void show4() {
//HashSet 去重且无序
//boolean add(E e)
HashSet<Integer> set = new HashSet<>();
// System.out.println(set.add(1));
set.add(2);
// System.out.println(set.add(1));
set.add(3);
set.add(44);
set.add(34);
set.contains(2);
// System.out.println(set);
// System.out.println("是否包含:"+set.contains(2));
//boolean remove 删除
System.out.println(set.remove(2));
// System.out.println(set.contains(2));
System.out.println(set.size());
//迭代
for(Integer i:set){
System.out.println(i);
}
//克隆
System.out.println(set.clone());
//清空
set.clear();
System.out.println("是否为空:"+set.isEmpty());
}
4.1.2 底层实现原理
HashSet底层是HashMap,HashMap的底层实现是哈希表
// 创建HashSet时HashSet无参构造会创建HashMap
// 向hashSet中存储元素,其实向HashMap中存储
HashSet<Integer> set = new HashSet<>(); //创建时创建HashMap
set.add(2); //实际是存储到HashMap中
HashSet(或者底层HashMap)创建时,默认容量是16,加载因子0.75
- 容量就是存储的个数
- 加载因子的作用是控制扩容的时机
什么时候触发开始扩容?
- 当存储的元素达到 初始容量*加载因子时,即达到16 X 0.75 = 12,就会扩容,扩容成原来的2倍
通过调整初始容量和加载因子改变性能,但是建议是不要改
ps: hashMap的底层原理在jdk1.8后变样了,后面在了解
4.1.3 去重原理
需求: 创建学生类,定义2个属性,定义有参无参构造方法, 创建HashSet集合,泛型指定成Student,存储5个学生, 要求存储的学生如果属性一致要去重
// 学生类,正常的属性,封装,构造,toString
public class Student {
private int age;
private String name;
// 省略setget方法
}
// 测试
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>( );
set.add(new Student(18,"老王"));
set.add(new Student(18,"老王"));
set.add(new Student(19,"老李"));
set.add(new Student(19,"老李"));
set.add(new Student(20,"老刘"));
set.add(new Student(20,"老刘"));
for (Student student : set) {
System.out.println(student );
}
}
// 结果是没有去重
为什么没有去重,通过源码发现,
- 存储的学生对象,其实是存储的存到hashmap的键上
- 然后通过存储的对象调用了hashcode方法,获得了地址值,但是学生类没有重写hashCode方法,所以调用的Object类的hashCode()方法,Object类的hashCode()方法是返回的对象地址,又因为每**
new一次地址值都不一样
**,所以即返回的每个对象地址值都不一样- 但是如果,发现源码中有当正在存储的元素与集合中已经存在元素地址值如果相等时 会再判断元素的equals方法
- 但是我们存储的元素的地址值都不一样,所以不会调用equals方法就直接存储到集合中了
去重原理:
- 先调用存储的元素的hashcode方法,获得哈希值
- 然后与集合中的元素的**
地址值判断,如果不一样直接存储
** - 如果存储的元素的地址值与集合中存在的元素的
地址值一样【如果两个对象的某些属性值相同,而其他属性值不同,但在 hashCode() 方法中只考虑了相同的属性,那么它们生成的哈希码也可能相同】,再比较equals方法
,判断对象属性是否相同 - 如果**
equals也判断相同,即认为重复,不存储
** - 如果**
equals判断不相同,即认为不重复,存储
**
4.2、TreeSet
TreeSet是Set集合的实现类,也是
不允许重复元素
,但是它存储的元素有序
!!会对存储的元素默认按照自然顺序
排序,另外此类也是不保证线程安全
4.2.1 演示方法
方法比较多,但常用的也是这些 (TreeSet不常用)
大部分方法都是常规方法,正常使用(添加,遍历,删除,大小,清空…)
public static void main(String[] args) {
//boolean add() 自然排序:从小到大排序且去重
TreeSet<Integer> set = new TreeSet<>();
set.add(98);
set.add(32);
set.add(154);
set.add(11);
set.add(11);
for(Integer i:set){
System.out.println(i);
}
System.out.println("-------------");
//boolean addAll(集合)
TreeSet<Integer> set2 = new TreeSet<>();
set2.addAll(set);
//迭代
for(Integer i :set2){
System.out.println(i);
}
//E ceiling(153) 返回此 set 中[大于等于给定元素的最小元素];
// 如果不存在这样的元素,则返回 null。
System.out.println(set.ceiling(153));
//E floor()
//clear()
//clone()
//contains()
//isEmpty()
//size()
}
}
4.1.2 排序去重的原理
需求: 创建学生类(自定义类),定义2个属性,定义有参无参构造方法, 创建TreeSet集合,泛型指定成Student,存储5个学生, 要求存储的学生如果属性一致要去重,按照年龄从小到大
发现无法去重,报错!!!
- 要想利用TreeSet排序,存储的元素必须实现Comparable接口,重写comparTo方法
- 当调用add方法存储元素时,会调用元素的comparTo进行运算
- 如果返回负数,放在二叉树左侧
- 如果返回正数,放在二叉树右侧
- 如果返回0,去除元素不放
// 学生类
public class Student implements Comparable<Student>{
private int age;
private String name;
// set get 构造略写
/**
* compareTo方法的返回值决定了元素的顺序以及是否去重
*
* 返回值为 0 直接去重
* 返回值为 负数 放根节点左侧
* 返回值为 正数 放根节点右侧
* -------------------------
* 存储完,树按照中序遍历取值
*------------------
* o是树结构上以前存储过的元素
* this是当前正在存的元素
*/
@Override
public int compareTo(Student o) {
System.out.println("this:" + this );
System.out.println("o:" + o );
return o.getAge() - this.getAge();
}
}
// 测试
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>( );
ts.add(new Student(18,"小美1"));
ts.add(new Student(18,"小美2"));
ts.add(new Student(19,"小帅3"));
ts.add(new Student(19,"小帅4"));
for (Student s : ts) {
System.out.println(s );
}
}
总结: 以后想要利用TreeSet进行排序去重,那么就得实现Comparable接口,重写comparTo方法,根据情况去写算法(确定如何正负零,可以试出来)
4.2.3 自然排序&比较器排序[扩展|了解]
自然排序其实就是指 实现了Comparable接口的,创建TreeSet集合时不指定排序规则,默认就是就这种自然排序
比较器排序, 在创建集合时传入
自定义的比较器对象
,存储元素时就会使用自定义的方法实现排序
演示: 自定义整型比较器,实现对存储整型Integer去重且倒序
// 自定义整型比较器
public class MyIntegerComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
// 创建集合时存入该比较器对象
public static void main(String[] args) {
// 创建集合时存入该比较器对象
TreeSet<Integer> set = new TreeSet<>(new MyIntegerComparator());
set.add(3);
set.add(3);
set.add(2);
set.add(5);
set.add(1);
set.add(4);
System.out.println(set );
}
总结:
- 自然排序简单,且jdk中默认是使用这种,一般都是从小到大
- 比较器排序,更灵活,可以自定义规则
- 自然排序是需要类实现Comparable接口的,但是如果说源码无法改动,即无法实现Comparable接口完成排序,此时就可以使用比较器排序
五、Map
5.1介绍
Map是一种映射关系的集合,能从键映射到值,他是一种特殊的集合,一次存储一对元素(键值对),即Map是双列集合。
ps:映射理解为就是查找
- Map中键不能重复,去重
- Map中一个键只能找到一个值(键找值,值不能找键,想想也是因为值可以重复)
Map是双列集合的接口,一般常用的是两个实现类:HashMap,TreeMap
5.2 HashMap【重点】
HashMap是Map的实现
- 底层是基于Hash表(jdk1.8以后底层是数组+链表+红黑树)
- 允许存储null值null键
- HashMap不保证线程安全
- Hashtable是线程安全的,不允许null值null键,除此之外与HashMap
HashMap方法演示
public class Demo4 {
public static void main(String[] args) {
HashMap<Integer, String> ish = new HashMap<>();
ish.put(1,"ss");
ish.put(1,"cc");
ish.put(2,"csd");
ish.put(4,"sac");
System.out.println(ish);
//v get(Object key)通过键找值
System.out.println(ish.get(1));
//判断是否包含某个键
System.out.println(ish.containsKey(4));
System.out.println(ish.containsValue("cc"));
//集合大小 size
System.out.println(ish.size());
//删除,通过键删,返回的是值,但是删除是删一对
ish.remove(1);
System.out.println(ish);
//清空集合
ish.clear();
System.out.println(ish);
}
}
5.2 迭代遍历
Map集合没有提供直接的遍历Map集合的方法,但是提供了
- 键集 Set ketSet(), 键集专门遍历键
- 值集 Collection values, 专门遍历值
- 键值映射集 Set<Map.Entry<K,V>>entrySet,专门遍历键值对
private static void show3() {
HashMap<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",1);
//获得键
Set<String> keySet = map.keySet();
System.out.println("键:");
for(String s :keySet){
System.out.print(" "+s);
}
System.out.println();
//获得值
Collection<Integer> values = map.values();
System.out.println("值:");
for(Integer i :values){
System.out.print(" "+i);
}
System.out.println();
//获得键和值
Set< Map.Entry<String,Integer> > entrySet = map.entrySet();
System.out.println("键和值:");
for(Map.Entry<String,Integer> result :entrySet){
Integer value = result.getValue();
String s = result.getKey();
System.out.print(" "+s+"="+value);
}
}
5.3 底层原理
HashMap底层是数组+链表+红黑树
HashMap底层的hash表就是一个数组,容量是16
- 数组存储的是链表
- 当put时候存储k-v时,算出key的hash值,当做数组的索引,存储到数组中
- 如果数组中这个位置,没有元素直接存储
- 如果数组中这个位置有元素,当作链表挂起
- 如果此位置链表长度已经>8时,链表就会转成红黑树
- 存储元素值达到阈值:初始容量*加载因子 = 16X0.75 会扩容为2倍
5.4 应用场景
HashMap所有应用场景都是基于映射,即只要有key—>value,或者说两个值之间有关系的都可以使用Map。
- 例如:球队和获奖的年份;省份的全称–>简称;
需求:键盘输入一串英文字符串"abcabcabc",计算出此字符串中每个字符出现的次数
public class Demo5 {
public static void main(String[] args) {
String s = "abcabcabc";
char[] charArray = s.toCharArray();
HashMap<Character, Integer> map = new HashMap<>();
for (char c : charArray) {
if (map.containsKey(c)) {
Integer i = map.get(c);
i++;
map.put(c,i);
}else{
map.put(c,1);
}
}
System.out.println(map);
}
}
HashMap可以当对象用
package com.qf;
import java.util.HashMap;
import java.util.Objects;
/**
* Fighting!!!
*
* @author LiWenJing
* @desc
* @since 2024/3/12 11:20
*/
public class Student2 {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Test2{
public static void main(String[] args) {
HashMap<String, Object> map = new HashMap<>();
map.put("name","老王");
map.put("age",18);
System.out.println(map);
}
}
5.5 其他Map
5.5.1 TreeMap
5.5.2 LinkedHashMap
LinkedHashMap保证插入顺序,去重
5.6 ConcurrentHashMap
HashMap是线程不安全
Hashtable是线程安全的,效率略慢
ConcurrentHashMap即保证线程安全,又效率高的双列集合
六、练习题
T1.从命令行读入一个字符串,表示一个年份,输出该年的世界杯冠军是哪支球队。
如果该年没有举办世界杯,则输出:没有举办世界杯。
import java.util.HashMap;
import java.util.Scanner;
/**
* Fighting!!!
*
* @author LiWenJing
* @desc
* @since 2024/3/11 19:59
*/
public class Demo1 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1930","乌拉圭");
map.put("1934","意大利");
map.put("1938","意大利");
map.put("1950","乌拉圭");
map.put("1954","德国");
map.put("1958","巴西");
map.put("1962","巴西");
map.put("1966","英格兰");
map.put("1970","巴西");
map.put("1974","德国");
map.put("1978","阿根廷");
map.put("1982","意大利");
map.put("1986","阿根廷");
map.put("1990","德国");
map.put("1994","巴西");
map.put("1998","法国");
map.put("2002","巴西");
map.put("2006","意大利");
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个年份,让我来告诉您这一年的世界杯冠军花落谁家:");
String key = sc.next();
if(map.containsKey(key)){
//通过键找到值
System.out.println("这一年的冠军是:"+map.get(key));
}else{
System.out.println("这一年没有举行世界杯哈");
}
}
}
T2. (Map)已知某学校的教学课程内容安排如下:
老师 课程
Tom CoreJava
John Oracle
Susan Oracle
Jerry JDBC
Jim Unix
Kevin JSP
Lucy JSP
完成下列要求:
1) 使用一个 Map,以老师的名字作为键,以老师教授的课程名作为值,表示上
述课程安排。
2) 增加了一位新老师 Allen 教 JDBC
3) Lucy 改为教 CoreJava
4) 遍历 Map,输出所有的老师及老师教授的课程
5) *利用 Map,输出所有教 JSP 的老师。
public class Demo {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
//(1)
map.put("Tom","CoreJava");
map.put("John","Oracle");
map.put("Susan","Susan");
map.put("Jerry","JDBC");
map.put("Jim","Unix");
map.put("Kevin","JSP");
map.put("Lucy","JSP");
//(2)增加了一位新老师 Allen 教 JDBC
map.put("Allen","JDBC");
//(3) Lucy 改为教 CoreJava
map.put("Lucy","CoreJava");
//(4)遍历 Map,输出所有的老师及老师教授的课程
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for(Map.Entry<String,String> entry :entrySet){
String key = entry.getKey();
String value = entry.getValue();
System.out.println("老师"+key+",教授的课程是:"+value);
}
//(5)*利用 Map,输出所有教JSP 的老师。
System.out.println("教JSP的老师有:");
Set<Map.Entry<String, String>> entrySet2 = map.entrySet();
for (Map.Entry<String,String> entry2 :entrySet2){
if(entry2.getValue().equals("JSP")){
System.out.println(entry2.getKey());
}
}
}
}
T3.*(Map)在原有世界杯 Map 的基础上,增加如下功能:
读入一支球队的名字,输出该球队夺冠的年份列表。
例如,读入“巴西”,应当输出:
1958 1962 1970 1994 2002
读入“荷兰”,应当输出
没有获得过世界杯
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* Fighting!!!
*
* @author LiWenJing
* @desc
* @since 2024/3/11 19:59
*/
public class Demo1 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1930","乌拉圭");
map.put("1934","意大利");
map.put("1938","意大利");
map.put("1950","乌拉圭");
map.put("1954","德国");
map.put("1958","巴西");
map.put("1962","巴西");
map.put("1966","英格兰");
map.put("1970","巴西");
map.put("1974","德国");
map.put("1978","阿根廷");
map.put("1982","意大利");
map.put("1986","阿根廷");
map.put("1990","德国");
map.put("1994","巴西");
map.put("1998","法国");
map.put("2002","巴西");
map.put("2006","意大利");
Scanner sc = new Scanner(System.in);
System.out.println("0.请输入一个年份,得知这一年的冠军");
System.out.println("1.请输入一支球队名称,得知它得冠军的年份");
while (true){
System.out.print("请输入您要访问的业务:");
int i = sc.nextInt();
switch (i){
case 0:
System.out.print("请输入一个年份:");
String key = sc.next();
if(map.containsKey(key)){
//通过键找到值
System.out.println("这一年的冠军是:"+map.get(key));
}else{
System.out.println("这一年没有举行世界杯哈");
}
break;
case 1:
System.out.print("请输入一支球队:");
String s = sc.next();
Set<Map.Entry<String, String>> entrySet = map.entrySet();
boolean flag = true;
for (Map.Entry<String, String> entry : entrySet) {
if(entry.getValue().equals(s)){
System.out.print(entry.getKey()+" ");
flag = false;
}
}
if(flag){
System.out.println("没有获得过世界杯");
}
System.out.println();
break;
default:
System.out.println("没有您访问的业务");
break;
}
}
}
}