HashMap:
HashMap集合也基于哈希表:
保证了键的唯一性,Map只针对键有效
并且元素的是无序的,存储与取出不一致
哈希表底层也依赖于:hashcode()与equals()方法
对于自定义类:该类要重写hashcode()和equals()方法
package org.westos;
public class Student {
String name;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
package org.westos.HashMap;
import java.util.HashMap;
import java.util.Set;
import org.westos.Student;
public class HAshMapDemo1 {
public static void main(String[] args) {
HashMap<Student,String> hm=new HashMap<Student,String>();
Student s1=new Student("王菲",45);
Student s2=new Student("杨千嬅",23);
Student s3=new Student("莫文蔚",44);
Student s4=new Student("谢春花",25);
Student s5=new Student("Adile",29);
Student s6=new Student("王菲",45);
Student s7=new Student("杨千嬅",23);
Student s8=new Student("莫文蔚",44);
Student s9=new Student("谢春花",25);
hm.put(s1, "北京");
hm.put(s2, "香港");
hm.put(s3, "香港");
hm.put(s4, "浙江");
hm.put(s5, "伦敦");
hm.put(s6, "北京");
hm.put(s7, "香港");
hm.put(s8, "香港");
hm.put(s9, "浙江");
System.out.println(hm);
Set<Student> set=hm.keySet();
for(Student s:set)
System.out.println(s+"---"+hm.get(s));
}
}
LinkedHashMap<K,V> :是Map接口基于哈希表和链接列表实现的
哈希表保证键的唯一性
链接列表保证元素有序性(存储和取出一致)
package LinkedHashMapDemo;
import java.util.ArrayList;
import java.util.LinkedHashMap;
public class LinkedHashMapDemo {
public static void main(String[] args) {
// 创建一个LinkedHashMap集合,该集合的键为ArrayList集合
LinkedHashMap<ArrayList<String>, String> lhm = new LinkedHashMap<ArrayList<String>, String>();
ArrayList<String> al = new ArrayList<String>();
al.add("111");
al.add("222");
ArrayList<String> al2 = new ArrayList<String>();
al2.add("111");
al2.add("222");
al2.add("333");
ArrayList<String> al3 = new ArrayList<String>();
al3.add("111");
al3.add("222");
al3.add("333");
ArrayList<String> al5 = new ArrayList<String>();
al5.add("111");
al5.add("222");
ArrayList<String> al6 = new ArrayList<String>();
al6.add("111");
al6.add("222");
al6.add("111");
al6.add("222");
lhm.put(al, "学");
lhm.put(al2, "习");
lhm.put(al3, "使我");
lhm.put(al6, "快乐");
lhm.put(al5, "呀");
// 遍历该集合
System.out.println(lhm);
for (ArrayList<String> al1 : lhm.keySet()) {
for (String str : al1)
System.out.print(str + "--");
System.out.println(lhm.get(al1));
}
}
}
TreeMap集合:
保证了键的的唯一性
元素根据键的高低进行排列
package TreeMap;
public class Student {
private String name;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
package TreeMap;
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
//创建TreeMap集合,并创建Comparator的匿名对象,重写Compare()方法
TreeMap<Student, String> tm = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
int a = s1.age - s2.age;
a = a == 0 ? s1.getName().compareTo(s2.getName()) : a;
return a;
}
});
//添加元素
Student s1 = new Student("杨过", 23);
Student s2 = new Student("郭靖", 23);
Student s3 = new Student("令狐冲", 25);
Student s4 = new Student("张无忌", 25);
Student s5 = new Student("韦小宝", 20);
Student s6 = new Student("韦小宝", 20);
tm.put(s1, "宋朝");
tm.put(s2, "宋朝");
tm.put(s3, "不知道朝");
tm.put(s4, "元朝");
tm.put(s5, "错朝");
tm.put(s6, "清朝");
System.out.println(tm);
//遍历元素
for(Student s:tm.keySet())
System.out.println(s+"---"+tm.get(s));
}
}
面试题:
HashMap集合与Hashtable的区别?
共同点:都是Map接口的实现类,都是基于哈希表的实现类
HashMap:线程不安全的类,不同步,执行效率高(允许键和值为null)
Hashtable:线程安全的类,同步的,执行效率低(不允许键和值为null)
线程安全的类:
StringBuffer:字符串缓冲区
Vector:List集合的
Hashtable:Map集合的
package Map;
import java.util.HashMap;
import java.util.Hashtable;
public class HashtableDemo {
public static void main(String[] args) {
Hashtable<String,Integer> ht=new Hashtable<String,Integer>();
//ht.put(null, null);//运行报错java.lang.NullPointerException,存储的键值码不能为null
//ht.put(null,2);
ht.put("qwer", 2);
//ht.put("a", null);
ht.put("asdf", 1);
ht.put("asdf", 1);
ht.put("zxcv", 3);
ht.put("bnm", 4);
ht.put("tyuiop", 1);
System.out.println(ht);
System.out.println("----------");
HashMap<String,Integer> hm=new HashMap<String,Integer>();
//hm.put(null, null);
hm.put("qwer",3 );
hm.put("asdf", null);
hm.put("bnm",1);
hm.put(null,2);
System.out.println(hm);
}
}
需求:
字符串:比如: aaaaabbbbcccddddee ,最终控制台要出现的结果:a(5)b(4)c(3)d(3)e(2)
package Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
// 给出一个字符串
String str = "aaaaaabbbbbbbbbbccccccdddddddddeeee";
// 创建一个TreeMap集合
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
// 将该字符串转换为字符数组
char[] ch = str.toCharArray();
// 遍历该数组
for (char ch1 : ch) {
// 当集合中没有存储该字符对应的键,获取该键对应的值为null
Integer i = tm.get(ch1);
if (i == null)
tm.put(ch1, 1);
else if (i != null)
tm.put(ch1, ++i);
}
System.out.println(tm);
Set<Character> set = tm.keySet();
StringBuffer sb = new StringBuffer();
System.out.println(sb);
for (Character ch2 : set)
sb.append(ch2 + "(" + tm.get(ch2) + ")");
String str1 = sb.toString();
System.out.println(str1);
}
}
Collection与Collections的区别:
Collection:是定层次单列集合的根接口,是一个集合,也是个接口
Collections:是针对集合操作的工具类
她的一些功能:
public static <T>int binarySearch(List<T> list,key):使用二分法查找该集合中的元素
public static T max(Collection c):获去该集合中的最大值
public static void reverse(List<T> list):将该集合中的元素反转
public static void Shuffle(List<T> List):将该集合元素的顺序打乱
public static void sort(List<T> list)将该集合的元素进行排序
package Collections;
public class Student {
String name;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
package Collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public class CollectionsDemo {
public static void main(String[] args) {
// 创建ArrayList集合,并添加元素
ArrayList<Student> al = new ArrayList<Student>();
Student s1 = new Student("林俊杰", 35);
Student s2 = new Student("周杰伦", 35);
Student s3 = new Student("王杰", 45);
Student s4 = new Student("陈百强", 62);
Student s5 = new Student("谭咏麟", 62);
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);
al.add(s5);
System.out.println(al);
for (Student s : al)
System.out.println(s);
System.out.println("-------------");
// 将该集合排序
Collections.sort(al, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
int a = s1.age - s2.age;
a = (a == 0) ? (s1.name.compareTo(s2.name)) : a;
return a;
}
});
for (Student s : al)
System.out.println(s);
System.out.println("-----------");
// 将该集合元素的顺序打乱
Collections.shuffle(al);
System.out.println(al);
for (Student s : al)
System.out.println(s);
System.out.println("-----------");
// 将该集合反转
Collections.reverse(al);
System.out.println(al);
for (Student s : al)
System.out.println(s);
System.out.println("-----------");
// 获取该集合的元素最大值
Student s = Collections.max(al, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
int a = s1.age - s2.age;
a = (a == 0) ? (s1.name.compareTo(s2.name)) : a;
return a;
}
});
System.out.println(s);
}
}
模拟斗地主的洗牌和发牌,发到每一个手上的牌是保证有序的.. 思考: 1)创建牌盒
创建两个集合:HashMap<Integer,String>,ArrayList<Integer> 2)装牌 定义花色数组和点数数组
从0开始编号,将编号和编号对应的牌都存储到HashMap集合中,同时往ArrayList单独存储编号 3)洗牌 洗的是编号 4)发牌
发的也是编号,为了保证牌有序,集合由TreeSet集合接收 5)看牌 封装功能
package Porker;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class porkerDemo {
public static void main(String[] args) {
// 定义花色与点数
String[] str = { "♥", "♠", "♣", "◆" };
String[] str2 = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2" };
// 创建牌盒HashMap获取牌与牌对应的编号,ArrayList获取牌对应的编号
HashMap<Integer, String> hm = new HashMap<Integer, String>();
ArrayList<Integer> al = new ArrayList<Integer>();
// 拼接花色与点数
int index = 0;
for (String str3 : str)
for (String str4 : str2) {
String str5 = str3.concat(str4);
hm.put(index, str5);
al.add(index);
index++;
}
// 获取小王
hm.put(index, "小王");
al.add(index);
index++;
// 获取大王
hm.put(index, "大王");
al.add(index);
System.out.println(hm);
// 洗牌
Collections.shuffle(al);
// 创建TreeSet集合分别获取三个玩家的牌和底牌对应的编号并排序
TreeSet<Integer> player1 = new TreeSet<Integer>();
TreeSet<Integer> player2 = new TreeSet<Integer>();
TreeSet<Integer> player3 = new TreeSet<Integer>();
TreeSet<Integer> dipai = new TreeSet<Integer>();
for (int i = 0; i < al.size(); i++) {
if (i >= al.size() - 3)
dipai.add(al.get(i));
else if (i % 3 == 1)
player1.add(al.get(i));
else if (i % 3 == 2)
player2.add(al.get(i));
else if (i % 3 == 0)
player3.add(al.get(i));
}
// 看牌
lookPoker("玩家1", player1, hm);
lookPoker("玩家2", player2, hm);
lookPoker("玩家3", player3, hm);
lookPoker("底牌", dipai, hm);
}
// 实现看牌的功能
public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {
System.out.println(name + "的牌是:");
for (Integer i : ts)
System.out.print(hm.get(i));
System.out.println();
}
}
Exception:
当程序出现一些问题的,可以是严重问题,可以是一种异常,将这些通常为Throwable
Throwable 类是 Java 语言中所有错误或异常的超类
Throwable
error
exception
举例:
张三去山上旅行
1)张三骑车去旅行,山路崩塌了,不能前行了----->不可抗力因素
2)张三骑车去旅行,骑着发现轮胎没气了------->需要检查的问题
3)骑着,山路有石子,他就非得往石子上骑,导致车胎没气了---->自己原因造成的,no zuo no die
不抗力因素----->error: 属于严重问题 内存溢出了 (加载页面中大量图片的时候,程序会挂掉---使用第三方的框架去处理:ImageLoader)
异常:
编译时期异常:只要出现的不是运行时期异常,统称为编译时期 日期的文本格式---解析 java.util.Date类型:ParseException:解析异常
编译时期异常:开发者必须处理!
运行时期异常:RuntimeException
编译通过了,但是开发者代码不严谨(NullPointerExceptino等等...)
一些代码
try里面的代码越少越好
代码包含了可能会出现问题的代码
}catch(异常类 异常类对象){
try出现异常了,描述的异常刚好就是catch的异常类,就会执行catch里面代码
处理异常
}
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo1 {
public static void main(String[] args) {
int a=1;
int b=0;
String str="1996--10--19";
try {
System.out.println(a/b);
}catch(ArithmeticException e) {
System.out.println("除数不能为0");
}
try {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy--MM--dd--hh");
Date d=sdf.parse(str);
}catch(ParseException e) {
System.out.println("解析异常");
e.printStackTrace();
}
}
}
如何处理多个异常
两个或两个以上的异常的时候怎么办?
try{
可能出现问题的代码
}catch(异常类名1 对象名1){
异常处理
}catch(异常类名2 对象名2(){
异常处理
}
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo2 {
public static void main(String[] args) {
int a = 1;
int b = 0;
String str = "1996--10--19";
try {
// 只会处理一个异常
SimpleDateFormat sdf = new SimpleDateFormat("yyyy--MM--dd--hh");
Date d = sdf.parse(str);
System.out.println(a / b);
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
} catch (ParseException e) {
System.out.println("解析异常");
e.printStackTrace();
}
}
}
Jdk7以后出现另一种方式处理多个异常
try{
可能出现问题的代码;
}catch(异常类名1 | 异常类名2 |... 对象名){
处理异常
}
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo3 {
public static void main(String[] args) {
int a=1;
int b=0;
String str="2018-5-20";
try {
System.out.println(a/b);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd-hh");
Date d=sdf.parse(str);
System.out.println(d);
//这多个异常类属于同一个级别
}catch(ArithmeticException | ParseException e) {
System.out.println("程序有问题");
e.printStackTrace();
}
}
}
编译时期异常和运行时期异常的区别?
编译时期:开发者必须进行显示处理,不处理,编译不能通过,
运行时期异常:无需进行显示处理,可以像编译时期一样进行处理
处理异常的第二种方式:使用throws 抛出异常 (跟在方法的后面)
xxx 返回值 方法名() throws 异常类名{
}
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo4 {
public static void main(String[] args) throws ParseException {
// method2();
method1();
}
public static void method1() throws ParseException {
String str="1996-2-4";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date d=sdf.parse(str);
System.out.println(d);
}
public static void method2()throws ArithmeticException {
int a=1;
int b=0;
System.out.println(a/b);
}
}
标准格式 try{ ... }catch(异常类 对象){ // 异常处理 } 执行try里面的代码
如果出现了问题,它会通过代码的问题创建一个异常对象,然后通过异常对象和catch里面的异常类是否一致
如果一致的情况,就会出现catch里面的代码,执行Throwable里面的方法
public String getMessage() :消息字符串
public String toString(): 异常的简短描述 ": ":由冒号和空格组成
public void printStackTrace():返回值void 直接调用, 包含了消息字符串,还有": "信息描述,具体出现异常的代码定位以及定位的源码上
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo5 {
public static void main(String[] args) {
String str="2018-5-21";
try {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date d=sdf.parse(str);
System.out.println(d);
System.exit(0);//在Java中执行finally语句之前jvm终止,才不会执行finally
System.out.println(d);
}catch(ParseException e) {
System.out.println(e.toString());
System.out.println("-------");
System.out.println(e.getMessage());
System.out.println("-----------");
e.printStackTrace();
}finally {
System.out.println("会不会执行呢");
}
}
}
throw:表示也是抛出异常,抛出的一个异常对象 (throw new 异常类名() :匿名对象的方式)
面试题:
throws和throw的区别?
throws:也是表示抛出异常,它后面跟的异常类名,并且可以多个异常类名中间逗号开
举例:
public void show() throws IoException,ClassNotFoundException{...}
在方法上抛出,由调用者处理
它表示抛出异常的可能性
throw:抛出的一个异常对象
在语句体中抛出的,由语句体进行处理
它表示抛出异常的肯定性
package Exception;
public class ExceptionDemo6 {
public static void main(String[] args) {
try {
method();
}catch(Exception e) {
System.out.println("出异常了");
e.printStackTrace();
}
}
public static void method() {
int []arr= {1,2,3,4,5};
for(int i=0;i<7;i++) {
if(i>=arr.length)
throw new ArrayIndexOutOfBoundsException();
System.out.println(arr[i]);
}
}
}
try...catch...finally
finally语句体是一定会执行的,除非是Jvm退出了
面试题:
如果catch里面有return 语句,finally中的代码还会执行,是在return语句之前执行还是return后执行?
finally中代码是一定会执行的,是在return前
package Exception;
public class ExceptionDemo7 {
public static void main(String[] args) {
System.out.println(get());
System.out.println(get2());
}
public static int get() {
int x = 0;
try {
int a=1;
int b=0;
System.out.println(a/b);
}catch(Exception e) {
// e.printStackTrace();
x=10;
return x;
/**
* try的代码出现问题了,执行catch中的语句,30赋值a,
* return 30(已经形成了一个回路径)finally代码一定会执行(除非Jvm) a = 40 ,在fianlly外面
* 有return a: a记录回路径的那个a,返回30
*/
}finally {
x=20;
}
return x;
}
public static int get2() {
int x = 0;
try {
int a=1;
int b=0;
System.out.println(a/b);
}catch(Exception e) {
// e.printStackTrace();
x=10;
// return x;
}finally {
x=20;
return x;
}
}
}
自定义异常类,两种方式
1)自定义一个类,这个继承自Exception
2)继承RuntimeException
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message) ;
}
}
自定义一个异常类
package Exception;
public class Student {
public void infer(int examation) throws Exception {
//判断成绩的方法
if(examation<0||examation>100)
throw new Exception("输入的成绩有问题");
else System.out.println("这个成绩还行");
}
}
package Exception;
import java.util.Scanner;
public class ExceptionDemo8 {
public static void main(String[] args) throws Exception {
//创建键盘录入对象
System.out.println("请输入一个成绩");
Scanner sc=new Scanner(System.in);
//创建Student对象
Student s=new Student();
int examation=sc.nextInt();
//调方法
s.infer(examation);
}
}
异常中的注意事项:
子类继承父类的时候的注意事项
1)子类重写父类的方法的时候,子类的方法的抛出的异常必须要么是父类的方法异常一样,要么是父类方法异常的子类
2)子类重写父类方法的时候,如果父类中的这个方法没有抛出异常,那么子类重写的这个方法也不能抛出异常,只能try...catch
package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo9 {
public static void main(String[] args) throws Exception {
Fu f = new Zi();
f.method();
f.show();
}
}
class Fu {
public void show() throws Exception {
}
public void method() {
}
}
class Zi extends Fu {
public void show() throws ArrayIndexOutOfBoundsException {
int[] arr = { 1 };
int i = 2;
if (i >= 1)
throw new ArrayIndexOutOfBoundsException("数组角标应该越界了");
else
System.out.println(arr[i]);
}
public void method() {
try {
String str = "2222-12-22";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh");
Date d = sdf.parse(str);
} catch (ParseException e) {
System.out.println("应该出问题了");
e.printStackTrace();
}
}
}