一.Comparator接口
*Comparator接口的使用
(1)使用Comparable接口定义排序顺序有局限性:实现此接口的类只能按compareTo()定义的这一种方式排序。
(2)如果同一类对象要有多种排序方式,应该为该类定义不同的比较器(实现Comparator接口的类)TreeSet有一个构造方法允许给定比较器,它就会根据给定的比较器对元素进行排序.
(3)Comparator接口中的比较方法
示例:public int compare(Object o1, Object o2);
该方法如果
返回 0,表示 o1 == o2
返回正数,表示 o1 > o2
返回负数,表示 o1 < o2
例(以学生成绩排名为例):
学生类(Student):
package comparator;
public class Student {
private String name;
private int score;//总分
private int math;//语文成绩
public Student() {
super();
}
public Student(String name, int score, int math) {
super();
this.name = name;
this.score = score;
this.math = math;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + ", math=" + math
+ "]";
}
}
以总分为第一排序准则类(ScoreRule):
package comparator;
import java.util.*;
public class ScoreRule implements Comparator<Student> {
@Override
public int compare(Student stu1, Student stu2) {
if(stu1.getScore()>stu2.getScore()){
return -1;
}else if(stu1.getScore()<stu2.getScore()){
return 1;
}else{
if(stu1.getMath()>stu2.getMath()){
return -1;
}else if(stu1.getMath()<stu2.getMath()){
return 1;
}else{
return stu1.getName().compareTo(stu2.getName());
}
}
}
}
以数学成绩为第一标准排序类(MathRule):
package comparator;
import java.util.Comparator;
public class MathRule implements Comparator<Student>{
@Override
public int compare(Student stu1, Student stu2) {
if(stu1.getMath()>stu2.getMath()){
return -1;
}else if(stu1.getMath()<stu2.getMath()){
return 1;
}else{
if(stu1.getScore()>stu2.getScore()){
return -1;
}else if(stu1.getScore()<stu2.getScore()){
return 1;
}else{
return stu1.getName().compareTo(stu2.getName());
}
}
}
}
测试TreeSet类:
package comparator;
import java.util.TreeSet;
public class TestSetDemo {
public static void main(String[] args) {
TreeSet<Student> set=new TreeSet<Student>(new ScoreRule());
set.add(new Student("独孤求败",786,145));
set.add(new Student("王磊",456,78));
set.add(new Student("王忠磊",564,97));
set.add(new Student("风清扬",786,123));
set.add(new Student("王磊",456,78));
set.add(new Student("王磊",456,78));
set.add(new Student("杨过",456,98));
set.add(new Student("令狐冲",556,86));
set.add(new Student("张无忌",665,100));
set.add(new Student("独孤求败",786,145));
set.add(new Student("孙悟空",754,147));
set.add(new Student("唐僧",453,67));
System.out.println("以总分为 排序第一标准:");
for(Student stu:set){
System.out.println(stu);
}
System.out.println();
TreeSet<Student> set1=new TreeSet<Student>(new MathRule());
set1.add(new Student("独孤求败",786,145));
set1.add(new Student("王磊",456,78));
set1.add(new Student("王忠磊",564,97));
set1.add(new Student("风清扬",786,123));
set1.add(new Student("王磊",456,78));
set1.add(new Student("王磊",456,78));
set1.add(new Student("杨过",456,98));
set1.add(new Student("令狐冲",556,86));
set1.add(new Student("张无忌",665,100));
set1.add(new Student("独孤求败",786,145));
set1.add(new Student("孙悟空",754,147));
set1.add(new Student("唐僧",453,67));
System.out.println("以数学成绩为第一排序标准:");
for(Student stu:set1){
System.out.println(stu);
}
}
}
运行结果为:
以总分为 排序第一标准:
Student [name=独孤求败, score=786, math=145]
Student [name=风清扬, score=786, math=123]
Student [name=孙悟空, score=754, math=147]
Student [name=张无忌, score=665, math=100]
Student [name=王忠磊, score=564, math=97]
Student [name=令狐冲, score=556, math=86]
Student [name=杨过, score=456, math=98]
Student [name=王磊, score=456, math=78]
Student [name=唐僧, score=453, math=67]
以数学成绩为第一排序标准:
Student [name=孙悟空, score=754, math=147]
Student [name=独孤求败, score=786, math=145]
Student [name=风清扬, score=786, math=123]
Student [name=张无忌, score=665, math=100]
Student [name=杨过, score=456, math=98]
Student [name=王忠磊, score=564, math=97]
Student [name=令狐冲, score=556, math=86]
Student [name=王磊, score=456, math=78]
Student [name=唐僧, score=453, math=67]
分析:例中分别以学生的总分和数学分数为第一标准进行了排序,属于同一对象多种排序,故我们实现了Comparator接口实现了接口中的public int compare(Object o1, Object o2)方法,分别制定了各种排序得规则(即比较器),TreeSet中的构造方法允许给定比较器,按照比较器进行排序。
二.Map集合
1.特点:
(1)实现Map接口的集合类用来存储“键-值”映射对。
(2)不能包含重复的键,每个键最多只能映射到一个值,值可以重复。
(3)JDK API中Map接口的实现类常用的有:
HashMap
TreeMap
Hashtable (不常用)
Properties
2.Map接口中的常用方法:
(1)Object put(Object key, Object value); //将指定的“键-值”对存入Map中
(2)Object get(Object key); //返回指定键所映射的值
(3)Object remove(Object key); //根据指定的键把此“键-值”对从Map中移除。
(4)boolean containsKey(Object key); //判断此Map是否包含指定键的“键-值”对。
(5)boolean containsValue(Object value); //判断此Map是否包含指定值的“键-值”对。
(6)boolean isEmpty(); //判断此Map中是否有元素。
(7)int size(); //获得些Map中“键-值”对的数量。
(8)void clear(); //清空Map中的所有“键-值”对。
(9)Set keySet(); //返回此Map中包含的键的Set集。
(10)Collection values(); //返回此Map中包含的值的Collection集。
(11)Set<Map.Entry<K,V>> entrySet() 将所有包含键-值对的Map.Entry收集到Set
3.Map.Entry接口:
*Map.Entry是Map中内部定义的一个接口,专门用来保存key value的内容。
4.HashMap类与TreeMap类
(1)HashMap存储结构使用哈希表,使用“键”进行散列存放。所以根据“键”去取“值”的效率很高。
(2)TreeMap中的“key-value”对的“key”必须是可“排序”的。
5.HashTable类
(1)旧版的Hashtable,操作大多跟HashMap相同,只是它保证线程的同步。
(2)它有一个子类Properties(属性集)比较常用:
*Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性集中每个键及其对应值都是一个字符串。
*不建议使用 put 和 putAll 这类存放元素方法,应该使用 setProperty(String key, String value)方法,因为存放的“键-值”对都是字符串。类似取值也应该使用getProperty(String key)。
例(以Properties类举例):
package mapdemo;
import java.util.Properties;
public class PropertiesDemo {
public static void main(String[] args) {
Properties pro=new Properties();
pro.setProperty("张三丰","149岁");
pro.setProperty("奥运会","08中国");
pro.setProperty("游泳冠军","孙杨");
pro.setProperty("六脉神剑","段誉");
pro.setProperty("降龙十八掌","郭靖");
System.out.println("根据键找到对应的值:"+pro.getProperty("奥运会"));
System.out.println(pro.getProperty("游泳冠军"," "));
System.out.println(pro.getProperty("iguihejg","没有 找到对应的值,这是默认值~~~ "));
}
}
运行结果为:
根据键找到对应的值:08中国
孙杨
没有 找到对应的值,这是默认值~~~
HashMap和Hashtable区别:
(1) HashMap不同步,Hashtable同步
(2) HashMap可以存储null键null值,Hashtable不可以
(3) HashMap多线程操作环境下效率高,Hashtable多线程操作环境下效率低
例(以Map集合及其常用方法为例):
package mapdemo;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<String, String> map=new HashMap<>();
map.put("country", "中国");
map.put("name", "令狐冲");
map.put("apple", "苹果");
map.put("banana", "香蕉");
map.put("sing", "唱歌");
map.put("map", "集合");
System.out.println("原始集合键值对数:"+map.size());
System.out.println("集合中以country为Key的键值是:"+map.get("country"));
map.remove("name");//移除name键值对
System.out.println("移除name集合中以name为Key的键值是:"+map.get("name"));
System.out.println("现在集合键值对数:"+map.size());
System.out.println("集合中包括key是banana的键值对吗? "+map.containsKey("banana"));
System.out.println("集合中包括value是苹果的键值对吗? "+map.containsValue("苹果"));
Set<String>set=map.keySet();
System.out.println("获取集合中所有的key,遍厉得:");
for(String str:set){
System.out.print(str+" ");
}
System.out.println();
System.out.println("获取集合中所有的value值,并遍厉得:");
Collection<String> set1=map.values();
for(String str:set1){
System.out.print(str+"\t");
}
System.out.println();
System.out.println("**********遍厉集合中的所有键值对*********");
Set<Map.Entry<String, String>> setEntry=map.entrySet();
for(Map.Entry<String, String> ma:setEntry){
System.out.println(ma.getKey()+"========>"+ma.getValue());
}
}
}
运行结果为:
原始集合键值对数:6
集合中以country为Key的键值是:中国
移除name集合中以name为Key的键值是:null
现在集合键值对数:5
集合中包括key是banana的键值对吗? true
集合中包括value是苹果的键值对吗? true
获取集合中所有的key,遍厉得:
banana country apple sing map
获取集合中所有的value值,并遍厉得:
香蕉 中国 苹果 唱歌 集合
**********遍厉集合中的所有键值对*********
banana========>香蕉
country========>中国
apple========>苹果
sing========>唱歌
map========>集合
三.异常机制
异常的概念:异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序
Java中如何进行异常处理:Java的异常处理是通过5个关键字来实现的:
(1)try执行可能产生异常的代码
(2)Catch捕获异常
(3)Finally无论是否产生异常总能执行的代码
*其上三个 关键字 都属于捕获异常的范畴
(4)throws声明方法可能要抛出的各种异常
*throws属于声明异常
(5)Throw手动跑出异常对象
*throw属于抛出异常
3.Java程序编译和运行时所发生的问题有两大类:
(1)错误(Error):JVM系统内部错误或资源耗尽等严重情况-属于JVM需要负担的责任
(2)异常(Exception):其它因编程错误或偶然的外在因素导致的一般性问题。
*程序员只能处理异常而对错误无能为力
4.异常处理机制的原理:Java程序在执行过程中如果出现异常,会自动生成一个异常类对象,该异常类对象将被自动提交给JVM(在程序没有显式处理异常的情下),这个过程称为抛出异常(throw)
5.异常的分类:
(1)检查时异常(E xception):SQLException,
IOException,
ClassNotFoundException,
......
例(检查时异常):
package exceptiondemo;
import java.io.IOException;
public class CheckExceptionDemo {
public static void main(String[] args) {
Runtime run=Runtime.getRuntime();
try {
run.exec("clac");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
运行结果为:
Cannot run program "clac": CreateProcess error=2, 系统找不到指定的文件。
(2)运行时异常(RunTimeException):NullPointerException,
ArithmeticExcepttion,
ClassCastExceptioion,
ArrayIndexOutOfBundsException,
.......
(3)常见异常:(RunTimeException)
ArithmeticException:数学计算异常
NullPointerException:空指针异常
ArrayOutOfBoundsException:数组索引越界异常
ClassCastException:类型转换异常
6.Exception与RuntimeException
(1)Exception在程序中是必须进行处理
(2)RuntimeException可以不使用try…catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。
7.处理异常的方法:
*使用try-catch块捕获异常,catch块可以有多个
格式如下:
public void method(){
try {
// 代码段(此处可能产生异常)
} catch (异常类型 ex) {
// 对异常进行处理的代码段
}
// 代码段
}
例(以0作为除数为例):
package exceptiondemo;
public class TryCatchDemo {
public static void main(String[] args) {
try {
int a=99;
int b=0;
int temp=a/b;
} catch (Exception e) {
System.out.println("产生异常了~~~");
System.out.println("输出捕获道德异常"+e.getMessage());
}
System.out.println("程序继续向下运行!!。。。。");
}
}
运行结果为:
产生异常了~~~
输出捕获道德异常/ by zero
程序继续向下运行!!。。。。
8.常见的异常类型:
异常类型 | 说明 |
Exception | 异常层次结构的父类 |
ArithmeticException | 算数错误情形,如以0作除数 |
ArrayIndexOutOfBoundsException | 数组下标越界 |
NullPointerException | 尝试访问null对象成员 |
ClassNotFoundException | 不能加载所需的类 |
IllegalArgumentException | 方法接收到非法参数 |
ClassCastException | 对象强制类型转换出错 |
NumberFormatException | 数字格式转换异常,例“abc”转换成数字 |
9.try--catch--finally:
(1)在try--catch模块后加上finally代码块,无论是否发生异常,finally中的代码都会执行
(2)有一种情况例外:在try--cathch块后加了System.exit(0),会直接关闭JVM
例(还是以0作除数为例):
package exceptiondemo;
public class FinallyDemo {
public static void main(String[] args) {
try {
int result=divide(99,0);
System.out.println("计算结果为:"+result);
} catch (Exception e) {
System.out.println("出现异常了~~~~");
System.out.println("输出异常信息:"+e.getMessage());
}finally{
System.out.println("进入finally块程序继续运行:");
int x=1;
int y=1;
int temp=x+y;
System.out.println("计算结果为:"+temp);
}
System.out.println("进入主方法程序继续向下运行!!!!!!");
}
public static int divide(int x,int y){
int result=x/y;
return result;
}
}
运行结果为:
出现异常了~~~~
输出异常信息:/ by zero
进入finally块程序继续运行:
计算结果为:2
进入主方法程序继续向下运行!!!!!!
10.多重catch块(引发多种类型的异常):
(1)排列catch块语句顺序:先子类后父类
(2)发生异常时按顺序逐个匹配
(3)只执行第一个与异常类型匹配的catch语句
格式:
public void method(){
try {
// 代码段
// 产生异常(异常类型2)
} catch (异常类型1 ex) {
// 对异常进行处理的代码段
} catch (异常类型2 ex) {
// 对异常进行处理的代码段
} catch (异常类型3 ex) {
// 对异常进行处理的代码段
}
// 代码段
}
例(挨个捕捉异常):
package exception;
public class RuntimeExceptionDemo {
public static void main(String[] args) {
int a=100;
int b=0;
String str=null;
int[] array=new int[5];
try{
array[5]=100;
str.equals("abc");
int c=a/b;
}catch(NullPointerException e){
System.out.println("空指针异常~~~");
}catch(ArithmeticException e){
System.out.println("算数异常~~~");
}catch(Exception e){
System.out.println("以上catch都没有捕获到异常,由最大父类Exception处理异常");
}finally{
System.out.println("进入finally块无论异常是否发生,都会执行");
}
System.out.println("main()方法执行完毕!");
}
}
运行结果为:
以上catch都没有捕获到异常,由最大父类Exception处理异常
进入finally块无论异常是否发生,都会执行
main()方法执行完毕!
11.try---finally:try…finally 不能捕获异常 ,仅仅用来当发生异常时,用来释放资源
格式:
public void method(){
try {
// 代码段 1
// 产生异常的代码段 2
}finally{
// 代码段 3
}
}
例(以0作除数为例):
package exceptiondemo;
public class TryFinallyDemo {
public static void main(String[] args) {
try {
int x=88;
int y=0;
int temp=x/y;
System.out.println("计算结果为:"+temp);
} finally {
System.out.println("用于释放资源");
}
}
}
运行结果为:
用于释放资源
Exception in thread "main" java.lang.ArithmeticException: / by zero
at exceptiondemo.TryFinallyDemo.main(TryFinallyDemo.java:9)
由结果可知try--finally不会捕获异常,只用于释放资源
12.throw与throws的区别:
(1)throw用来手动抛出异常
(2)Throws用于方法声明处,用于抛出该方法体内部可能发生的异常类型。一旦在方法声明处通过throws抛出某种类型的异常,则在该方 法体内部就不用处理该类型的异常,交给方法调用处处理该类型的异常。
例1(手动抛出异常):
package throwdemo;
public class ThrowDemo {
public static void main(String[] args) {
try {
int[] a=new int[3];
System.out.println(a[4]);
//throw new ArrayIndexOutOfBoundsException();
} catch (Exception e) {
System.out.println("发生了数组越界异常~~~");
}
}
}
运行结果为:
发生了数组越界异常~~~
例2(throws声明异常):
package throwsdemo;
public class ThrowsDemo {
public static void main(String[] args) {
try {
int result=divide(88,2);
System.out.println("计算结果为:"+result);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
public static int divide(int x,int y) throws Exception{
int result=x/y;
return result;
}
}
运行结果为:
计算结果为:44
*注意在调用异常声明方法是,如果不知道如何处理异常,也可使用throw关键字继续将异常抛出,这样程序也可以编译通过,但程序一旦发生异常,如果程序没有被处理,程序就会非正常终止
例:
package throwsdemo;
public class ThrowsDemo01 {
public static void main(String[] args) throws Exception {
int result=divide(88,0);
System.out.println("计算结果为:"+result);
}
public static int divide(int x,int y) throws Exception{
int result=x/y;
return result;
}
}
运行结果为:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at throwsdemo.ThrowsDemo01.divide(ThrowsDemo01.java:10)
at throwsdemo.ThrowsDemo01.main(ThrowsDemo01.java:6)
13.自定义异常:
(1)创建自定义异常:继承自Exception 。习惯上包装一下父类的构造方法。
格式:
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String msg) {
super(msg);
}
}
(2)使用自定义异常:
格式:
public String[] createArray(int length) throws MyException {
if (length < 0) {
throw new MyException("数组长度小于0,不合法");
}
return new String[length];
}
例1(以上述自定义异常和使用自定义异常为例):
自定义异常类(继承父类Exception):
package throwexception;
public class DivideByMinusException extends Exception{
public DivideByMinusException(){
super();
}
public DivideByMinusException(String message){
super(message);
}
}
测试自定义异常类:
package throwexception;
public class ThrowExceptionDemo {
public static void main(String[] args) {
try {
int result=divide(55,-5);
System.out.println("计算结果为:"+result);
} catch (DivideByMinusException e) {
System.out.println(e.getMessage());
}
}
public static int divide(int x,int y) throws DivideByMinusException{
if(y<0){
throw new DivideByMinusException("被除数是负数~~~");
}
int result=x/y;
return result;
}
}
运行结果为:
被除数是负数~~~
例2(以货船载货为例自定义异常):
自定义LoadException异常:
package boat;
public class LoadException extends Exception{
public LoadException(){
super();
}
public LoadException(String message){
super(message);
}
}
货船模拟装货类:
package boat;
public class Boat {
private static final int MAX_STORE=1000;
private int currentStore;
public void load(int num) throws LoadException{
System.out.println("货船装货前当前载货量:"+currentStore);
currentStore+=currentStore;//模拟装货
System.out.println("货船装货后的当前载货量:"+currentStore);
if(currentStore>MAX_STORE){
System.out.println("已超载,货船面临乘船危险~~");
}
}
}
测试货船装货类:
package boat;
import java.util.Scanner;
public class TestBoat {
public static void main(String[] args) {
Boat bo=new Boat();
while(true){
Scanner scan=new Scanner(System.in);
System.out.print("请输入要载入载货量:");
int cur=scan.nextInt();
try {
bo.load(cur);
} catch (LoadException e) {
System.out.println("输出 捕获的异常:"+e.getMessage());
break;
}
scan.close();
}
}
}
*小结(finally易错点):
例:
package easyeorror;
public class FinallyDemo {
public static void main(String[] args) {
int result=divide(4,6);
System.out.println("所返回 的结果是:"+result);
}
public static int divide(int x,int y){
try {
int temp=x+y;
return temp;
} catch (Exception e) {
System.out.println("发生异常了~~~~~~~");
}finally{
int result=x*y;
return result;
}
}
}
运行结果为:
所返回 的结果是:24
【本次总结完毕】
2018.1.12
转载于:https://blog.51cto.com/13501268/2060694