Java第三部分

第十章 异常处理

  • 1,异常概述

    • 在程序中,错误可能产生于程序员没有预料到的各种情况,或者是超出了程序员可控范围的环境因素,如用户的坏数据、试图打开一个根本不存在的文件等。

    • Java中这种在程序运行时可能出现的一些错误称为异常。异常是一个在执行期间发生的事件,它中断了正在执行的程序的正常指令流。

    • 通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时在其他地方处理异常。
      在Java中,如果某个方法抛出异常,既可以在当前方法中进行捕捉,然后处理该异常,也可以将异常向上抛出,由方法调用者来处理。

  • 2,捕捉异常

    • Java语言的异常捕获结构由try、catch和finally 3部分组成。

    • try语句存放的是可能发生异常的Java语句;catch程序块在try语句块之后,用来激发被捕获的异常;finally语句块是异常处理结构的最后执行部分,无论try块中的代码如何退出,都将执行finally块。

    • 当try代码块中的语句发生异常时,程序就会调转到catch代码块中执行,执行完catch代码块中的程序代码后,将继续执行catch代码块后的其他代码,而不会执行try代码块中发生异常语句后面的代码。

    • Java的异常处理是结构化的,不会因为一个异常影响整个程序的执行。

    • 通常,异常处理用以下三个函数来获取异常的有关信息。

      • getMessage();输出错误性质
      • toString();给出异常的类型与性质
      • printStackTrace();指出异常的类型、性质、栈层次及出现在程序中的位置。
  • 3,自定义异常

    • 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户只需继承Exception类即可自定义异常类。

    • 在程序中使用自定义异常类,大体上可分为以下几个步骤:

      • 1.创建自定义异常类;
      • 2.在方法中通过throw关键字抛出异常对象;
      • 3.如果在当前抛出异常的方法中处理异常,可以使用try-catch语句块捕获并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,
        继续进行下一步操作。
      • 4.在出现异常方法的调用者中捕获并处理异常。
    • throws关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分隔。

      • 使用throws关键字将异常抛给上一级后,如果不想处理该异常,可以继续向上抛,但最终要有能够处理该异常的代码。

      • 如果是Error、RuntimeException或他们的子类,可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

    • throw关键字通常用于方法体中并且抛出一个异常对象。程序在执行到throw语句时立即终止,它后面的语句都不执行。

      • 可以使用多个catch语句来捕捉异常。产生什么异常,会使程序跳转到相应的catch异常语句块中。

      • 由于Exception是所有异常类的父类,如果将catch(Exception e)代码块放在其他两个代码块的前面,后面的代码块将永远得不到执行,也就没有什么意义了,所以catch语句的顺序不可调换。

  • 4,运行时异常

    • RuntimeException异常是程序运行过程中产生的异常。
      Java类库的每个包中都定义了异常类,所有这些类都是Throwable类的子类。

    • Throwable类派生了两个子类,分别是Exception和Error类。Error类及其子类用来描述Java运行系统中的内部错误以及资源耗尽的错误,这类错误比较严重。

    • Exception类又根据错误发生的原因分为RuntimeException异常和除RuntimeException之外的异常。

    • 5,异常的使用原则

      • Java异常强制用户去考虑程序的强健性和安全性。

      • 异常处理不应该用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应的处理。

      • 编写代码处理某个方法可能出现的异常时,可以遵循以下几条原则:

        • 1.在当前方法声明中使用try-catch语句捕获异常。
        • 2.一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
        • 3.如果父类抛出多个异常,则覆盖方法必须抛出那些异常的一个子集,不能抛出新异常。

第十一章 集合类

  • 1,集合类概述

    • java.util包中提供了一些集合类,这些集合类又被称为容器。提到容器不难想到数组,集合类与数组的不同之处是,数组的长度是固定的,集合的长度是可变的;

    • 数组用来存放基本数据类型,集合用来存放对象的引用。

    • 常用的集合有List集合、Set集合和Map集合,其中List与Set继承了Collection接口,各接口还提供了不同的实现类。

  • 2,Collection接口

    • Collection接口是层次结构中的根接口。构成Collection的单位称为元素。

    • Collection接口通常不能直接使用,但该接口提供添加元素、删除元素、管理数据的方法。

    • 由于List与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。

    • Collection接口中常用的方法:

      • add(E e);//将指定的对象添加到该集合中
      • remove(Object o);//将指定的对象从该集合中移除
      • isEmpty();//返回boolean值,用于判断当前集合是否为空
      • iterator();//返回在此Collection的元素上进行迭代的迭代器。用于遍历集合中的对象。
      • size();//返回int型值,获取该集合中元素的个数

      • 通常遍历集合,都是通过迭代器(Iterator)来实现。collection接口中的iterator()方法可返回在此Collection进行迭代的迭代器。

  • 3,List集合

    • List集合包括List接口以及List接口的所有实现类。

    • List集合中的元素允许重复,各元素的顺序就是对象插入的顺序。类似Java数组,用户可通过索引(元素在集合中的位置)来访问集合中的元素。

    • List接口:List接口继承了Collection接口,因此包含了Collection中的所有方法,此外,List接口还定义了一下两个非常重要的方法。

      get(int index):获得指定索引位置的元素
      set(int index,Object obj):将集合中指定索引位置的对象修改为指定的对象。
      
    • List接口的实现类:List接口的常用实现类有Vector、ArrayList与LinkedList。

      • Vector:内部是数组数据结构,是同步的,增删,查询都很慢!

      • ArrayList类内部是数组数据结构,实现了可变的数组,容许保存所有的元素,包括null,并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或删除对象的速度较慢。

      • LinkedList类采用链表结构保存对象,是不同步的。这种结构的优点是便于向集合中插入和删除对象,需要向集合中插入、删除对象时,使用LinkedList类实现的List集合的效率较高;但对于随机访问集合中的对象,使用LinkedList类实现List集合的效率较低。

      • 与数组相同,集合的索引也是从0开始的。

        常用的方法:

        addFirst();addLast();  jdk1.6后为offerFirst();offerLast();
        
        getFirst();getLast();  jdk1.6后为peekFirst();peekLast();
        
        removeFirst();removeLast();  jdk1.6后为pollFirst();pollLast();
        
  • 4,Set集合

    • Set集合中的对象不按特定的方式排序,只是简单地把对象加入到集合中,但Set集合中不能包含重复对象。Set集合由Set接口和Set接口的实现类组成。

    • Set接口继承了Collection接口,因此包含collection接口的所有方法。

    • Set接口常用的实现类有HashSet类和TreeSet类:

      • HashSet类:

        • HashSet类实现Set接口,由哈希表(实际上是一个HashMap实例)支持,即内部数据是哈希表,是不同步的。
          它不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null元素。

        • 通过对象的hashCode()和equals()方法来完成对象的唯一性。先判断对象的hashCode值,如果不同,则不用去判断equals方法;如果相同,再判断对象的equals方法是否为true。

        • 记住:如果元素要存储到HashSet集合中,必须覆盖hashCode()和equals()方法。

        • 一般情况下,如果定义的类会产生很多对象,比如人,学生等通常都要覆盖equals和hashCode方法,建立对象判断是否相同的依据。

      • TreeSet类:

        • TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,因此,TreeSet类实现的Set集合在遍历集合时按照自然顺序递增排序,也可以按照指定比较器递增排序,即可以通过比较器对用TreeSet类实现的

        • Set集合中的对象进行排序。
          判断元素唯一的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。

        • TreeSet对元素进行排序的方式一:
          让元素自身具备比较功能,元素(对象)就要实现Comparable接口,覆盖compareTo方法。

        • TreeSet集合排序的第二种方式:
          让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。
          将该类对象作为参数传递给TreeSet集合的构造函数。

  • 5,Map集合

    • Map没有继承Collection接口,其提供的是key到value的映射。

    • Map中不能包含相同的key,每个key只能映射一个value。key还决定了存储对象在映射中的存储位置,但不是由key对象本身决定的,
      而是通过一种“散列技术”进行处理,产生一个散列码的整数值,散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。

    • Map集合包括Map接口以及Map接口的所有实现类。

    • Map接口提供了将key映射到值得对象。一个映射不能包含重复的key,每个key最多只能映射到一个值。

    • Map接口中提供了集合常用方法:

      • put(K key,V value);//向集合中添加指定的key与value的映射关系

      • containsKey(Object key);//如果此映射包含指定key的映射关系,则返回true

      • containsValue(Object value);//如果此映射将一个或多个key映射到指定值,则返回true

      • get(Object key);//如果存在指定的key对象,则返回该对象对应的值,否则返回null

      • keySet();//返回该集合中的所有key对象形成的Set集合

      • values();//返回该集合中所有值对象形成的Collection集合。
    • Map接口的实现类:Map接口常用的实现类有HashMap和TreeMap

      • 建议用HashMap类实现Map集合,因为由HashMap类实现的Map集合添加和删除映射关系效率更高。

      • HashMap是基于哈希表的Map接口的实现,HashMap通过哈希码对其内部的映射关系进行快速查找;

      • 而TreeMap中的映射关系存在一定的顺序,如果希望Map集合中的对象也存在一定的顺序,应该使用TreeMap类实现Map集合。

      • HashMap类:该类是基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。

      • HashMap通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

      • TreeMap类:该类不仅实现了Map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。

      • 但在添加、删除和定位映射关系时,TreeMap类比HashMap类性能稍差。

      • 由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是null。

第十二章 泛型技术

  • 在JDK1.5版本中提供了泛型概念,泛型实质上就是使程序员定义安全的类型。

  • 在没有泛型之前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向下转型”及“向上转型”操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以在此提供了泛型机制。

  • “向上转型”是安全的,而如果进行“向下转型”操作时用错了类型,或者并没有执行该操作,就会出现异常。通常并不会出现语法错误,所以可以被编译器接受,但在执行时会出现异常。

  • 泛型的语法为:类名 T代表一个类型名称

  • 使用泛型定义的类在声明该类对象时可以根据不同的需求指定真正的类型,而在使用类中的方法传递或返回数据类型时将不再需要进行类型转换操作,而是使用在声明泛型类对象时“<>”符号中设置的数据类型。

  • 在定义泛型类时,一般类型名称使用T来表达,而容器的元素使用E来表达。

  • 泛型的常规用法

    • 1.在定义泛型类时可以声明多个类型。

    • 语法:

      MutiOverClass<T1,T2>;
      这样在实例化指定类型的对象时就可以指定多个类如:MutiOverClass<Boolean,Float>=new MutiOverClass<Boolean,Float>();
      
    • 2.定义泛型类时可以声明数组。

    可以在使用泛型机制时声明一个数组,但不可以使用泛型来建立数组的实例。

    • 3.集合类声明容器的元素。

      可以使用K和V两个字符代表容器中的键值和与键值相对应的具体值。
      
    • 泛型的高级用法:泛型的高级用法包括限制泛型可用类型和使用类型通配符等。

    • 1.限制泛型可用类型
      语法:class 类名称;其中anyClass指某个接口或类。
      使用泛型限制后,泛型类的类型必须实现或继承了anyClass这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。

    • 2.使用类型通配符
      在泛型机制中,提供了类型通配符,其主要作用是创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类。

      语法:泛型类名称<? extends List> a=null;
      <? extends List>表示类型未知,但需要使用该泛型对象时,可以单独实例化。
      这里需要注意的是,使用通配符声明的实例化的对象不能对其加入新的信息,只能获取或删除。
      
    • 3.泛型类型限制除了可以向下限制之外,还可以进行向上限制,只要在定义时使用super关键字即可。

      例如,“A<? super List> a=null;”这样定义后,对象只接受List接口或上层父类类型。
      
    • 4.继承泛型类与实现泛型接口
      定义为泛型的类和接口也可以被继承与实现。例如:class SubClass

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章