2019-08-17 Day16 Set、Map以及异常处理


目的

  • 了解泛型,学习泛型方法
  • 学习Set集合,明白其原理和子类,掌握其使用方法
  • 学习Map集合,理解其特点,分辨键值对之间的关系
  • 了解异常处理的原因,掌握其几种方法

泛型

概念

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型);也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

种类

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法;今天的重点是泛型类

泛型类

泛型类型用于类的定义中,被称为泛型类;通过泛型可以完成对一组类的操作对外开放相同的接口;最典型的就是各种容器类,如:List、Set、Map
泛型类的最基本写法:

class 类名称 <泛型标识:可以随便写任意标识号,标识指定的泛型的类型>{
}
class GenericTest{
    int age;
    T a1;
    T a2;

    public void test(T a1, T a2){
        this.a1 = a1;
        this.a2 = a2;

        System.out.println(a1.equals(a2));
    }
}

Set集合

概念

Java中的Set和正好和数学上直观的集(set)的概念是相同的;Set最大的特性就是不允许在其中存放的元素是重复的;根据这个特点,我们就可以使用Set这个接口来实现前面提到的关于商品种类的存储需求;Set可以被用来过滤在其他集合中存放的元素,从而得到一个没有包含重复新的集合
Set是Collection的子接口,Set集合中的元素是无序,无重复的,如果试图把两个相同的元素加入到同一个Set集合中,则添加操作会失败,add()方法返回false;HashSet,TreeSet,LinkedHashSet是Set集合最常见的三个实现类

HashSet

HashSet是Set常见的实现类,它有如下特点:
1.它不允许出现重复元素
2.不保证集合中元素的顺序
集合是无序的,添加的顺序和存储的顺序无关,并且集合使用默认排序

具体使用

        HashSet names = new HashSet<>();
        names.add("jack");
        names.add("merry");
        names.add("abc");

        names.removeIf(ele -> {
            return ele.compareTo("c") > 0;
                });

List里面的方法在Set里面都可以使用,这里就不详细列出了

TreeSet

TreeSet是可以实现排序等功能的集合,它在对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中
TreeSet是如何对对象进行排序的呢?

在JDK中,有一部分类实现了Comparable接口,如Integer,Double和String等,Comparable接口有一个compareTo(Object o)方法,它返回整数类型,对于表达式x.compareTo(y),如果返回值为0,表示x和y相等,如果返回值大于0,表示x大于y,如果小于0,表示x小于y
TreeSet调用对象的compareTo()方法比较集合中对象的大小,然后进行升序排序,这种方式称为自然排序.
客户化排序:
java.util.Comparator接口用于指定具体的排序方式,它有个compare(Object obj1,Object obj2),用于比较两个对象的大小;当表达式compare(x,y)的值大于0,表示x大于y,小于0,表示x小于y,等于0,表示x等于y,如果想让TreeSet进按照Customer对象的name属性进行降序排列,可以先创建实现Comparator接口的类CustomerComparator

第一种排序方法

        TreeSet score = new TreeSet<>(new Comparator() {
            @Override
            public int compare(Person person, Person t1) {
                return person.compareTo(t1);
            }
        });

第二种排序方法

必须实现Comparable借口的compareTo方法

        TreeSet score = new TreeSet<>((Person p1,Person p2) -> p1.compareTo(p2));

        Person p1 = new Person("jack",20);
        Person p2 = new Person("jack",30);
        Person p3 = new Person("rose",20);

        score.add(p1);
        score.add(p2);
        score.add(p3);

        // equals 比较的是对象内部的内容
        // 使用的两个对象必须实现Comparable接口的compareTo方法
        // 在compareTo里面实现具体该如何比较
        System.out.println(score);
        if(p1.hashCode() == p1.hashCode()){
            System.out.println("相同");
        }
class Person implements Comparable{
    String name;
    int age;

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        // 1.判断o对象是不是person的一个对象
        if (o instanceof Person){
            Person o1 = (Person) o;
            // 自己规定比较的策略
            if (this.age != o1.age){
                return this.age - o1.age;
            }else{
                // 年龄相同的情况下 再比较姓名的字母
                return this.name.compareTo(o1.name);
            }
        }else{
            return -1;
        }
    }
}

Map

概念

Map集合没有继承Collection接口,其提供的是key到value的映射,Map中不能包含相同的key值,每个key只能映射一个相同的value;key值还决定了存储对象在映射中的存储位置;但不是key对象本身决定的,而是通过散列技术进行处理,可产生一个散列码的整数值,散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置;Map集合包括Map接口以及Map接口所实现的类

Map集合和Collection集合的区别:
Map集合是有Key和Value的,Collection集合是只有Value,而其实Collection集合底层也是有Key和Value,只是隐藏起来

Map接口的实现类:HashMap、TreeMap

image.png

代码实例

        // key不能重复 可以是任意的对象类型 通常使用字符串
        HashMap score = new HashMap<>();

        // 添加对象:键值对
        score.put("Chinese",89);
        score.put("Math",94);
        score.put("English",92);

        // 更改某个键对应的值
        score.put("Chinese",92);

        // 获取键值对的个数
        score.size();

        // 获取所有的key
        System.out.println(score.keySet());

        // 获取所有的值
        System.out.println(score.values());

        // 获取Entry:key-value
        System.out.println(score.entrySet());

        // 获取一个键key对应的值
        System.out.println(score.get("English"));

        // 键值对的遍历
        // 1.通过遍历key来得到每一个key对应的值
        for(String key:score.keySet()){
            // 通过key得到值
            int s = score.get(key);
            System.out.println("key:"+key+" value:"+s);
        }

        System.out.println("------------------------------------");
        // 2.通过entrySet 得到Entry对象的集合
        //   一个Entry管理一个键值对 getKey getValue
        Set> entrys = score.entrySet();
        for (Map.Entry entry: entrys){
            // 得到Entry对应的Key
            String key = (String)entry.getKey();

            // 获取key对应的值
            Integer value = (Integer)entry.getValue();

            System.out.println("key:"+key+" value:"+value);
        }

异常处理

概念

异常的英文单词是exception,字面翻译就是“意外、例外”的意思,也就是非正常情况;事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误;比如使用空的引用、数组下标越界、内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图;错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的;假若程序在运行期间出现了错误,如果置之不理,程序便会终止或直接导致系统崩溃,显然这不是我们希望看到的结果;因此,如何对运行期间出现的错误进行处理和补救呢?Java提供了异常机制来进行处理,通过异常机制来处理程序运行期间出现的错误;通过异常机制,我们可以更好地提升程序的健壮性

Java异常类层次结构图

2.jpg

异常处理最基本方法:

try{
    执行的代码
    可能会出现的异常
    一旦出现异常 系统会自动为我们创建一个异常对象 并抛出
}catch((异常对象)NullPointerException e){
    如果需要自己处理异常就catch
}catch(IOException e){
    如果有多个异常 可以使用多个catch来捕获
    如果有多个异常 catch的顺序是从小到大 因为多态
}catch(Exception1 e){

}finally{
    不管有没有异常finally都会被执行
    处理资源回收 网络连接 数据库连接 文件指针 I/O流
}

注意:如果异常出现,后面的代码将不会执行

代码实例

使用catch处理异常

        int a = 0;
        int b = 20;

        FileReader fr = null;
        try {
            int c = b / 1;
            System.out.println("hello");

            fr = new FileReader("");
        }catch (ArithmeticException e){
            System.out.println(e.getMessage());// getMessage获取异常的详细信息
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                fr.close();
            }catch (IOException e){

            }
        }

使用throws抛出异常

    public static void test() throws FileNotFoundException,NullPointerException{// 多个异常用逗号隔开
        FileReader fr = new FileReader("");
    }

使用throw抛出一个自己创建的异常对象

    public static void test2() throws IllegalAccessException{
        //······
        if (2 > 1){
            throw new IllegalAccessException();
        }
    }

自定义异常类

能够自己定义输出内容,更快地找到出现问题的位置

class PXDException extends Exception{
    // 1.提供一个无参构造方法
    public PXDException(){

    }

    // 2.提供一个有参构造方法 参数是一个字符串
    public PXDException(String desc){
        super(desc);
    }
}

使用自定义异常

    public static void test3() throws PXDException{
        //······
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stackTrace[2];
        String detail = e.getFileName()+"->"+e.getMethodName()+"->"+e.getLineNumber();
        throw new PXDException("自己的异常类:无所作为"+detail);
    }

捕获自定义异常

        try {
            TException.test3();
        } catch (PXDException e) {
            e.printStackTrace();
        }

心得体会

今天的内容比较枯燥,需要记住的内容很多,上课的时候不是很清楚;后来写来一个个回顾,让知识点清晰了不少,也记住了不少

你可能感兴趣的:(2019-08-17 Day16 Set、Map以及异常处理)