**
Map
**
上一篇文章主要提到了Collection集合以及它的实现类们,而Collection都是单列集合,也就是一个集合中储存的元素都是一个一个的。而Map是一个双列集合,集合中的元素是一对一对的存储的。
一个元素包含两个值(一个key一个value),数据类型可以相同也可以不同。key不可以重复,value可以重复,且一个key对应一个value。
Map集合有三种实现类:
1.HashMap集合是Map接口的一个实现类。底层是一个哈希表,所以它是无序的
2.HashTable集合也是Map接口的一个实现类,与HashMap很相似,不同之处在于HashTable不可以存储null值,null键
3.LinkedHashMap集合是HashMap的一个子类,底层是哈希表加一个链表,所以它是一个有序的集合
我们先在代码上看一下HashMap对象的创建和常用的方法:
Map<String,String> map=new HashMap<>();
//Map接口常用方法
//put方法:
String v1=map.put("郑恺", "杨颖");//郑恺代表key值
System.out.println("v1:"+v1);//key值不重复,返回null
String v2=map.put("郑恺", "苗苗");
System.out.println("v2:"+v2);//key值重复,返回被替换的value
System.out.println(map);
System.out.println("==============");
//remove:
Map<String,Integer> map2=new HashMap<>();
map2.put("赵丽颖",168);
map2.put("林志玲",178);
map2.put("迪丽热巴",170);
System.out.println(map2);
Integer i1=map2.remove("林志玲");//根据key来删除,返回其value
System.out.println(i1);
System.out.println(map2);
System.out.println("==============");
//get:
Integer i=map2.get("迪丽热巴");//根据key来查找,返回其value
System.out.println(i);
System.out.println(map2);
结果
v1:null
v2:杨颖
{郑恺=苗苗}
==============
{林志玲=178, 赵丽颖=168, 迪丽热巴=170}
178
{赵丽颖=168, 迪丽热巴=170}
==============
170
{赵丽颖=168, 迪丽热巴=170}
通过上面的代码,我们更清晰的了解到Map集合中的元素,是成对存在的。一个元素就是key=value的格式。
下面我们来看一下Map集合的遍历(分为三步):
迭代器方法
//1.Map中的KeySet方法,把集合的key值取出来,储存到一个set集合中
Set<String> set=map2.keySet();
//2.通过迭代器遍历set集合:
Iterator<String> it=set.iterator();
while(it.hasNext())
{
String key=it.next();
Integer value=map2.get(key);//3.再通过键找值
System.out.println(key+"="+value);
}
System.out.println();
增强for循环方法
//2.增强for循环:
for(String key:set)
{
Integer value2=map2.get(key);//3.再通过键找值
System.out.println(key+"="+value2);
}
两种方式的结果
赵丽颖=168
迪丽热巴=170
赵丽颖=168
迪丽热巴=170
赵丽颖=168
迪丽热巴=170
赵丽颖=168
迪丽热巴=170
Map集合这样的双列集合让我们在统计与组合元素上方便了很多,下面是两个小练习,可以体会一下Map集合的妙用。
第一个练习:统计输入的字符个数,key存储字符,value存储数目。
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str=sc.next();
HashMap<Character,Integer> hashmap=new HashMap<>();
for(char c:str.toCharArray())
{
if(hashmap.containsKey(c))
{
Integer num=hashmap.get(c);
num++;
hashmap.put(c, num);
}
else
hashmap.put(c, 1);
}
System.out.println(hashmap);
结果
请输入一个字符串:
asdasjkldhsadjnksahddndhasdhioawndjsbkadbuaisdj;asdk[admsdfhadjd
{a=11, b=2, d=15, f=1, h=5, i=2, j=5, k=4, l=1, m=1, n=3, o=1, s=9, u=1, w=1, ;=1, [=1}
第二个练习:做一个斗地主的小游戏,要求把三个人的牌与底牌打印出来,要求派牌的时候要随机,打印牌的时候由小到大。
//1.准备牌:
HashMap<Integer,String> poker=new HashMap<>();//储存牌(包括数字和花色)
ArrayList<Integer> poker_index=new ArrayList<>();//储存牌的索引
List<String> colors=List.of("♥️","♠️","♣️","♦️");
List<String> number=List.of("2","A","K","Q","J","10","9","8","7","6","5","4","3");
int index=0;
poker.put(index, "Joker");
poker_index.add(index);
index++;
poker.put(index, "joker");
poker_index.add(index);
index++;
for(String num:number)
{
for(String col:colors)
{
poker.put(index, col+num);
index++;
poker_index.add(index);
}
}
//2.洗牌:
Collections.shuffle(poker_index);
//3.发牌:
ArrayList<Integer> player01=new ArrayList<>();
ArrayList<Integer> player02=new ArrayList<>();
ArrayList<Integer> player03=new ArrayList<>();
ArrayList<Integer> Last_card=new ArrayList<>();//底牌
for(int i=0;i<poker_index.size();i++)
{
Integer in=poker_index.get(i);
if(i>=51)
{//先发底牌
Last_card.add(in);
}
else if(i%3==0)
{
player01.add(in);
}
else if(i%3==1)
{
player02.add(in);
}
else if(i%3==2)
{
player03.add(in);
}
}
//4.排序
Collections.sort(player01);
Collections.sort(player02);
Collections.sort(player03);
Collections.sort(Last_card);
//5.看牌
for(Integer key:Last_card)
{
String value=poker.get(key);
System.out.print(value);
}
System.out.println();
for(Integer key:player01)
{
String value=poker.get(key);
System.out.print(value);
}
System.out.println();
for(Integer key:player02)
{
String value=poker.get(key);
System.out.print(value);
}
System.out.println();
for(Integer key:player03)
{
String value=poker.get(key);
System.out.print(value);
}
System.out.println();
结果
joker♦️Q♥️9
♣️A♦️A♥️K♥️Q♣️Q♥️J♦️J♥️10♣️9♥️8♣️8♥️7♥️6♦️4♠️3♣️3♥️2
Joker♠️2♥️A♠️A♣️K♠️Q♠️J♣️J♠️10♦️9♦️8♥️5♣️5♦️5♣️4♥️3♦️3
♣️2♦️2♠️K♦️K♣️10♦️10♠️9♠️8♠️7♣️7♦️7♠️6♣️6♦️6♠️5♥️4♠️4
通过上面两个小游戏我们可以更深入的理解Map集合。
**
Java的异常处理
**
Java有一个类叫Throwable,它是所有异常类的根类,所有的异常类都是由他继承。
而异常分为两种,一种是错误,一种是异常。
错误是不可以处理的,因为这是系统内部的错误,运行时报错。主要分为内存溢出和系统崩溃。
我们来看一个错误
int[] array=new int[1024*1024*1024];
//这是一个错误,内存溢出
结果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at Error_and_Exception.Error_and_Exception_pricatice.main(Error_and_Exception_pricatice.java:43)
而异常是可以处理的,甚至有可以不处理的异常,比如RuntimeException以及它的子类都可以不处理。
下面是一个异常(传递的参数与自己定义的格式不相符)
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM--dd");
Date date=null;
date=sdf.parse("2000--0513");
结果
java.text.ParseException: Unparseable date: "2000--0513"
at java.base/java.text.DateFormat.parse(DateFormat.java:395)
at Error_and_Exception.Error_and_Exception_pricatice.main(Error_and_Exception_pricatice.java:33)
在说如何处理这个异常的时候,我们先来看一下异常处理的过程:
1.JVM检测出异常,创建一个异常对象,包含了产生的(内容,原因,位置)
2.在出现异常的方法中若没有try catch语句,就抛给方法的调用者main
3.main中也没有try catch就把异常抛给main调用者JVM
4.JVM做两件事:
1.把这个异常对象以红色打印到控制台
2.中断处理
了解完过程,我们来看一下异常处理的两种方式:
1.throws
2.try catch
针对上面的异常案例,第一种处理方法
public static void main(String[] args) throws ParseException{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM--dd");
Date date=null;
date=sdf.parse("2000--0513");
}
这一种处理方式是把这个异常给抛出(throws),交给虚拟机处理,至于throws后面的语句是不同类型的异常,有很多种需要大家自己去了解,这里就不多说了。
第二种处理方法
public static void main(String[] args) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM--dd");
Date date=null;
try {
date=sdf.parse("2000--0513");
} catch (ParseException e) {
e.printStackTrace();
System.out.println("错误!");
}
finally //finally代码块是一定会执行的
{
System.out.println("这是finally代码块的代码");
}
}
第二种处理方式就不把错误抛给虚拟机处理了,我们自己处理。try代码块里面写有可能出异常的代码,若真的发生了异常,catch就会捕获到然后执行catch代码块的代码。
第二种处理方式的结果
java.text.ParseException: Unparseable date: "2000--0513"
at java.base/java.text.DateFormat.parse(DateFormat.java:395)
at Error_and_Exception.Error_and_Exception_pricatice.main(Error_and_Exception_pricatice.java:33)
错误!
这是finally代码块的代码
最后我们来说一个throw关键字,它的作用是抛出一个异常(与throws不同,throw关键字必须写在方法内部,throws要写在方法头)
下面是代码展示throw的作用
public static void main(String[] args) throws ArrayIndexOutOfBoundsException,NullPointerException {
int[] array={1,2,3};
method(array,3);
}
public static void method(int[] array,int index) throws ArrayIndexOutOfBoundsException,NullPointerException
{
if(index<0||index>array.length)
{
throw new ArrayIndexOutOfBoundsException("索引异常");
}
if(array==null)
{
throw new NullPointerException("传递空数组");
}
System.out.println(array[index]);
}
上面的代码在mian函数中调用了一个方法,参数传递了一个数组和一个用于数组索引的数字。考虑到这样的参数可能产生两种异常,一种是索引越界异常,一种是空指针异常(就是传递了一个空数组)。对应这两种情况,我们在写完判定条件后分别throw了ArrayIndexOutOfBoundsException(“索引异常”)与NullPointerException(“传递空数组”)。
下面是使用throw关键字的注意事项:
1.throw关键字必须写在方法的内部
2.throw关键字后new的对象必须是Exception或Exception的子类对象
3.throw关键字抛出后必须进行处理:
throw关键字后面创建的是RunTimeException或者RunTimeException的子类,我们可以不处理把它交给JVM
throw关键字后面的是创建编译异常,必须用throws或者try catch
4.若我们调用了一个可能产生异常的方法,例如下面的method方法,那么调用方法也必须throws该异常
5.若可能产生多个异常,我们也要抛出多个异常
这次就到这里,下次更新有关线程的知识