Java学习总结——(Map集合,Comparator接口,异常等)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习总结——(Map集合,Comparator接口,异常等)相关的知识,希望对你有一定的参考价值。

一.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)不能包含重复的键,每个键最多只能映射到一个值,值可以重复。

3JDK APIMap接口的实现类常用的有:

    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.EntryMap中内部定义的一个接口,专门用来保存key  value的内容。

4.HashMap类与TreeMap

1HashMap存储结构使用哈希表,使用“键”进行散列存放。所以根据“键”去“值”的效率很高

2TreeMap中的“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中国

孙杨

没有 找到对应的值,这是默认值~~~

  1. HashMapHashtable区别:

    (1) HashMap不同步,Hashtable同步

    (2) HashMap可以存储nullnull值,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========>集合

三.异常机制

  1. 异常的概念:异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序

  2. 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.ExceptionRuntimeException

1Exception在程序中是必须进行处理

2RuntimeException可以不使用trycatch进行处理,但是如果有异常产生,则异常将由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---finallytryfinally 不能捕获异常 ,仅仅用来当发生异常时,用来释放资源

格式:

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.throwthrows的区别:

(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("发生了数组越界异常~~~");

        }

    }

 

}

运行结果为:

发生了数组越界异常~~~

2throws声明异常):

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

 

 

 

 

 

 

 

 

以上是关于Java学习总结——(Map集合,Comparator接口,异常等)的主要内容,如果未能解决你的问题,请参考以下文章

Java常用集合知识点总结

201621123037 《Java程序设计》第9周学习总结

java集合入门和深入学习,看这篇就差不多了

Java集合深入学习总结-LinkedHashMap

Java集合框架总结——Map接口的使用

面试3-java集合类总结(Map)