首页 > 编程语言 > 详细

java基础学习(六)

时间:2021-04-03 19:42:47      阅读:14      评论:0      收藏:0      [点我收藏+]

java基础学习(六)

十八、异常处理
十九、java集合、泛型、枚举

十八、异常处理

  • 常见运行时异常

  • 异常类型 说明
    ArithmeticException 算术错误异常,如以零做除数
    ArraylndexOutOfBoundException 数组索引越界
    ArrayStoreException 向类型不兼容的数组元素赋值
    ClassCastException 类型转换异常
    IllegalArgumentException 使用非法实参调用方法
    lIIegalStateException 环境或应用程序处于不正确的状态
    lIIegalThreadStateException 被请求的操作与当前线程状态不兼容
    IndexOutOfBoundsException 某种类型的索引越界
    NullPointerException 尝试访问 null 对象成员,空指针异常
    NegativeArraySizeException 再负数范围内创建的数组
    NumberFormatException 数字转化格式异常,比如字符串到 float 型数字的转换无效
    TypeNotPresentException 类型未找到
  • 常见非运行时异常

  • ClassNotFoundException 没有找到类
    IllegalAccessException 访问类被拒绝
    InstantiationException 试图创建抽象类或接口的对象
    InterruptedException 线程被另一个线程中断
    NoSuchFieldException 请求的域不存在
    NoSuchMethodException 请求的方法不存在
    ReflectiveOperationException 与反射有关的异常的超类
  • Error(错误)和 Exception(异常)都是 java.lang.Throwable 类的子类,在 Java 代码中只有继承了 Throwable 类的实例才能被 throw 或者 catch

  • Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类,Exception 是程序正常运行过程中可以预料到的意外情况,并且应该被开发者捕获,进行相应的处理。Error 是指正常情况下不大可能出现的情况,绝大部分的 Error 都会导致程序处于非正常、不可恢复状态。所以不需要被开发者捕获。

    Error 错误是任何处理技术都无法恢复的情况,肯定会导致程序非正常终止。并且 Error 错误属于未检查类型,大多数发生在运行时。Exception 又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源码里必须显示的进行捕获处理,这里是编译期检查的一部分。不检查异常就是所谓的运行时异常,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译器强制要求。

    如下是常见的 Error 和 Exception:

    1)运行时异常(RuntimeException):

    • NullPropagation:空指针异常;
    • ClassCastException:类型强制转换异常
    • IllegalArgumentException:传递非法参数异常
    • IndexOutOfBoundsException:下标越界异常
    • NumberFormatException:数字格式异常

    2)非运行时异常:

    • ClassNotFoundException:找不到指定 class 的异常
    • IOException:IO 操作异常

    3)错误(Error):

    • NoClassDefFoundError:找不到 class 定义异常
    • StackOverflowError:深递归导致栈被耗尽而抛出的异常
    • OutOfMemoryError:内存溢出异常
  • 运行时异常和非运行时异常

    (1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

    当出现RuntimeException的时候,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。

    出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。

    如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。

    (2)非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如 IOException、SQLException 等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。

  • try {
        逻辑程序块
    } catch(ExceptionType1 e) {
        处理代码块1
    } catch (ExceptionType2 e) {
        处理代码块2
        throw(e);    // 再抛出这个"异常"
    } finally {
        释放资源代码块
    }
    
  • 可以使用以下 3 个方法输出相应的异常信息。

    • printStackTrace() 方法:指出异常的类型、性质、栈层次及出现在程序中的位置(关于 printStackTrace 方法的使用可参考《Java的异常跟踪栈》一节)。
    • getMessage() 方法:输出错误的性质。
    • toString() 方法:给出异常的类型与性质。
  • 要注意异常类的父子关系在捕捉时的代码顺序

  • java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只回收堆内存中对象所占用的内存。

    所以为了确保一定能回收 try 块中打开的物理资源,异常处理机制提供了 finally 代码块,并且 Java 7 之后提供了自动资源管理(Automatic Resource Management)技术

  • 先执行finally语句再执行return,但是如果finally中有修改变量,则不会发生修改,仍然返回try和catch中的变量值

  • 自动资源管理:

    • Java 7 增加了一个新特性,该特性提供了另外一种管理资源的方式,这种方式能自动关闭文件,被称为自动资源管理(Automatic Resource Management)

    • try (声明或初始化资源语句) {
          // 可能会生成异常语句
      } catch(Throwable e1){
          // 处理异常e1
      } catch(Throwable e2){
          // 处理异常e1
      } catch(Throwable eN){
          // 处理异常eN
      }
      //当 try 代码块结束时,自动释放资源。不再需要显式的调用 close() 方法,该形式也称为“带资源的 try 语句”。
      
    • 注意:

      1. try 语句中声明的资源被隐式声明为 final,资源的作用局限于带资源的 try 语句。
      2. 可以在一条 try 语句中声明或初始化多个资源,每个资源以;隔开即可。
      3. 需要关闭的资源必须实现了 AutoCloseable 或 Closeable 接口。
    • Closeable 是 AutoCloseable 的子接口,Closeable 接口里的 close() 方法声明抛出了 IOException,因此它的实现类在实现 close() 方法时只能声明抛出 IOException 或其子类;AutoCloseable 接口里的 close() 方法声明抛出了 Exception,因此它的实现类在实现 close() 方法时可以声明抛出任何异常。

    • java7举例:

      public class AutoCloseTest {
          public static void main(String[] args) throws IOException {
              try (
                      // 声明、初始化两个可关闭的资源
                      // try语句会自动关闭这两个资源
                      BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
                      PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))) {
                  // 使用两个资源
                  System.out.println(br.readLine());
                  ps.println("hello");
              }
          }
      }
      //Java 7 几乎把所有的“资源类”(包括文件 IO 的各种类、JDBC 编程的 Connection 和 Statement 等接口)进行了改写,改写后的资源类都实现了 AutoCloseable 或 Closeable 接口。
      
    • Java 9 再次增强了这种 try 语句。Java 9 不要求在 try 后的圆括号内声明并创建资源,只需要自动关闭的资源有 final 修饰或者是有效的 final (effectively final),Java 9 允许将资源变量放在 try 后的圆括号内

    • Java 9举例:

      public class AutoCloseTest {
          public static void main(String[] args) throws IOException {
              // 有final修饰的资源
              final BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
              // 没有显式使用final修饰,但只要不对该变量重新赋值,该变量就是有效的
              final PrintStream ps = new PrintStream(new FileOutputStream("a. txt"));
              // 只要将两个资源放在try后的圆括号内即可
              try (br; ps) {
                  // 使用两个资源
                  System.out.println(br.readLine());
                  ps.println("hello");
              }
          }
      }
      
  • 声明异常和抛出异常:

    • throws 用来声明一个方法可能抛出的所有异常信息,表示出现异常的一种可能性,但并不一定会发生这些异常;throw 则是指拋出的一个具体的异常类型,执行 throw 则一定抛出了某种异常对象。
    • 通常在一个方法(类)的声明处通过 throws 声明方法(类)可能拋出的异常信息,而在方法(类)内部通过 throw 声明一个具体的异常信息。
    • throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。
  • 多异常捕获(java7)

    • try{
          // 可能会发生异常的语句
      } catch (IOException | ParseException e) {
          // 调用方法methodA处理
      }
      
    • 捕获多种类型的异常时,多种异常类型之间用竖线|隔开。

    • 捕获多种类型的异常时,异常变量有隐式的 final 修饰,因此程序不能对异常变量重新赋值。

  • 自定义异常

    • <class><自定义异常名><extends><Exception>
      
    • 自定义异常类一般包含两个构造方法:一个是无参的默认构造方法,另一个构造方法以字符串的形式接收一个定制的异常消息,并将该消息传递给超类的构造方法。

    • class IntegerRangeException extends Exception {
          public IntegerRangeException() {
              super();
          }
          public IntegerRangeException(String s) {
              super(s);
          }
      }
      
  • JDK自带记录日志类

    • java.util.logging

    • 级别依次降低

    • 级别 SEVERE WARNING INFO CONFIG FINE FINER FINEST
      调用方法 severe() warning() info() config() fine() finer() finest()
      含义 严重 警告 信息 配置 良好 较好 最好
    • Logger 的默认级别是 INFO,比 INFO 级别低的日志将不显示。Logger 的默认级别定义在 jre 安装目录的 lib 下面。

    • 所以在默认情况下,日志只显示前三个级别

    • 可以使用 setLevel 方法设置级别,例如logger.setLevel(Level.FINE);可以将 FINE 和更高级别的都记录下来。另外,还可以使用 Level.ALL 开启所有级别的记录,或者使用 Level.OFF 关闭所有级别的记录。

      注意:如果将记录级别设计为 INFO 或者更低,则需要修改日志处理器的配置。默认的日志处理器不会处理低于 INFO 级别的信息。

    • 可以通过编辑配置文件来修改日志系统的各种属性。在默认情况下,配置文件存在于 jre 安装目录下“jre/lib/logging.properties”。要想使用另一个配置文件,就要将 java.util.logging.config.file 特性设置为配置文件的存储位置,并用下列命令启动应用程序。

    • java -Djava.util.logging.config.file = configFile MainClass
      

      日志管理器在 JVM 启动过程中初始化,这在 main 执行之前完成。如果在 main 中调用System.setProperty("java.util.logging.config.file",file),也会调用LogManager.readConfiguration()来重新初始化日志管理器。

      要想修改默认的日志记录级别,就需要编辑配置文件,并修改以下命令行。

      .level=INFO
      

      可以通过添加以下内容来指定自己的日志记录级别

      Test.Test.level=FINE
      

      也就是说,在日志记录器名后面添加后缀 .level。

      在稍后可以看到,日志记录并不将消息发送到控制台上,这是处理器的任务。另外,处理器也有级别。要想在控制台上看到 FINE 级别的消息,就需要进行下列设置。

      java.util.logging.ConsoleHandler.level=FINE
      

      注意:在日志管理器配置的属性设置不是系统属性,因此,用-Dcom.mycompany.myapp.level=FINE启动应用程序不会对日志记录器产生任何影响。

十九、java集合、泛型、枚举

1. 总论:

  • Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类

  • 技术分享图片

  • 技术分享图片

  • 黄色块为集合的接口,蓝色块为集合的实现类。表 1 介绍了这些接口的作用。

    表 1 Java集合接口的作用

    接口名称 作 用
    Iterator 接口 集合的输出接口,主要用于遍历输出(即迭代访问)Collection 集合中的元素,Iterator 对象被称之为迭代器。迭代器接口是集合接口的父接口,实现类实现 Collection 时就必须实现 Iterator 接口。
    Collection 接口 是 List、Set 和 Queue 的父接口,是存放一组单值的最大接口。所谓的单值是指集合中的每个元素都是一个对象。一般很少直接使用此接口直接操作。
    Queue 接口 Queue 是 Java 提供的队列实现,有点类似于 List。
    Dueue 接口 是 Queue 的一个子接口,为双向队列。
    List 接口 是最常用的接口。是有序集合,允许有相同的元素。使用 List 能够精确地控制每个元素插入的位置,用户能够使用索引(元素在 List 中的位置,类似于数组下标)来访问 List 中的元素,与数组类似。
    Set 接口 不能包含重复的元素。
    Map 接口 是存放一对值的最大接口,即接口中的每个元素都是一对,以 key?value 的形式保存。

    对于 Set、List、Queue 和 Map 这 4 种集合,Java 最常用的实现类分别是 HashSet、TreeSet、ArrayList、ArrayDueue、LinkedList 和 HashMap、TreeMap 等。表 2 介绍了集合中这些常用的实现类。

    表 2 Java集合实现类的作用

    类名称 作用
    HashSet 为优化査询速度而设计的 Set。它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,实现比较简单
    TreeSet 实现了 Set 接口,是一个有序的 Set,这样就能从 Set 里面提取一个有序序列
    ArrayList 一个用数组实现的 List,能进行快速的随机访问,效率高而且实现了可变大小的数组
    ArrayDueue 是一个基于数组实现的双端队列,按“先进先出”的方式操作集合元素
    LinkedList 对顺序访问进行了优化,但随机访问的速度相对较慢。此外它还有 addFirst()、addLast()、getFirst()、getLast()、removeFirst() 和 removeLast() 等方法,能把它当成栈(Stack)或队列(Queue)来用
    HsahMap 按哈希算法来存取键对象
    TreeMap 可以对键对象进行排序

2.Collection接口

  • 方法名称 说明
    boolean add(E e) 向集合中添加一个元素,如果集合对象被添加操作改变了,则返回 true。E 是元素的数据类型
    boolean addAll(Collection c) 向集合中添加集合 c 中的所有元素,如果集合对象被添加操作改变了,则返回 true。
    void clear() 清除集合中的所有元素,将集合长度变为 0。
    boolean contains(Object o) 判断集合中是否存在指定元素
    boolean containsAll(Collection c) 判断集合中是否包含集合 c 中的所有元素
    boolean isEmpty() 判断集合是否为空
    Iteratoriterator() 返回一个 Iterator 对象,用于遍历集合中的元素
    boolean remove(Object o) 从集合中删除一个指定元素,当集合中包含了一个或多个元素 o 时,该方法只删除第一个符合条件的元素,该方法将返回 true。
    boolean removeAll(Collection c) 从集合中删除所有在集合 c 中出现的元素(相当于把调用该方法的集合减去集合 c)。如果该操作改变了调用该方法的集合,则该方法返回 true。
    boolean retainAll(Collection c) 从集合中删除集合 c 里不包含的元素(相当于把调用该方法的集合变成该集合和集合 c 的交集),如果该操作改变了调用该方法的集合,则该方法返回 true。
    int size() 返回集合中元素的个数
    Object[] toArray() 把集合转换为一个数组,所有的集合元素变成对应的数组元素。
  • Collections 类操作集合类

    1. 排序

      • Collections 提供了如下方法用于对 List 集合元素进行排序。
        • void reverse(List list):对指定 List 集合元素进行逆向排序。
        • void shuffle(List list):对 List 集合元素进行随机排序(shuffle 方法模拟了“洗牌”动作)。
        • void sort(List list):根据元素的自然顺序对指定 List 集合的元素按升序进行排序。
        • void sort(List list, Comparator c):根据指定 Comparator 产生的顺序对 List 集合元素进行排序。
        • void swap(List list, int i, int j):将指定 List 集合中的 i 处元素和 j 处元素进行交换。
        • void rotate(List list, int distance):当 distance 为正数时,将 list 集合的后 distance 个元素“整体”移到前面;当 distance 为负数时,将 list 集合的前 distance 个元素“整体”移到后面。该方法不会改变集合的长度。
    2. 查找替换操作

      • Collections 还提供了如下常用的用于查找、替换集合元素的方法。
        • int binarySearch(List list, Object key):使用二分搜索法搜索指定的 List 集合,以获得指定对象在 List 集合中的索引。如果要使该方法可以正常工作,则必须保证 List 中的元素已经处于有序状态。
        • Object max(Collection coll):根据元素的自然顺序,返回给定集合中的最大元素。
        • Object max(Collection coll, Comparator comp):根据 Comparator 指定的顺序,返回给定集合中的最大元素。
        • Object min(Collection coll):根据元素的自然顺序,返回给定集合中的最小元素。
        • Object min(Collection coll, Comparator comp):根据 Comparator 指定的顺序,返回给定集合中的最小元素。
        • void fill(List list, Object obj):使用指定元素 obj 替换指定 List 集合中的所有元素。
        • int frequency(Collection c, Object o):返回指定集合中指定元素的出现次数。
        • int indexOfSubList(List source, List target):返回子 List 对象在父 List 对象中第一次出现的位置索引;如果父 List 中没有出现这样的子 List,则返回 -1。
        • int lastIndexOfSubList(List source, List target):返回子 List 对象在父 List 对象中最后一次出现的位置索引;如果父 List 中没有岀现这样的子 List,则返回 -1。
        • boolean replaceAll(List list, Object oldVal, Object newVal):使用一个新值 newVal 替换 List 对象的所有旧值 oldVal。
    3. 复制

      • Collections 类的 copy() 静态方法用于将指定集合中的所有元素复制到另一个集合中。执行 copy() 方法后,目标集合中每个已复制元素的索引将等同于源集合中该元素的索引。

        copy() 方法的语法格式如下:

        void copy(List <? super T> dest,List<? extends T> src)
        

        其中,dest 表示目标集合对象,src 表示源集合对象。

        注意:目标集合的长度至少和源集合的长度相同,如果目标集合的长度更长,则不影响目标集合中的其余元素。如果目标集合长度不够而无法包含整个源集合元素,程序将抛出 IndexOutOfBoundsException 异常。

3.List集合

1.ArrayList 类

  • ArrayList 类实现了可变数组的大小,存储在内的数据称为元素。它还提供了快速基于索引访问元素的方式,对尾部成员的增加和删除支持较好。使用 ArrayList 创建的集合,允许对集合中的元素进行快速的随机访问,不过,向 ArrayList 中插入与删除元素的速度相对较慢。

    ArrayList 类的常用构造方法有如下两种重载形式:

    • ArrayList():构造一个初始容量为 10 的空列表。
    • ArrayList(Collection<?extends E>c):构造一个包含指定 Collection 元素的列表,这些元素是按照该 Collection 的迭代器返回它们的顺序排列的。

    ArrayList 类除了包含 Collection 接口中的所有方法之外,还包括 List 接口中提供的如表 1 所示的方法。

    方法名称 说明
    E get(int index) 获取此集合中指定索引位置的元素,E 为集合中元素的数据类型
    int index(Object o) 返回此集合中第一次出现指定元素的索引,如果此集合不包含该元 素,则返回 -1
    int lastIndexOf(Object o) 返回此集合中最后一次出现指定元素的索引,如果此集合不包含该 元素,则返回 -1
    E set(int index, Eelement) 将此集合中指定索引位置的元素修改为 element 参数指定的对象。 此方法返回此集合中指定索引位置的原元素
    List subList(int fromlndex, int tolndex) 返回一个新的集合,新集合中包含 fromlndex 和 tolndex 索引之间 的所有元素。包含 fromlndex 处的元素,不包含 tolndex 索引处的 元素

    注意:当调用 List 的 set(int index, Object element) 方法来改变 List 集合指定索引处的元素时,指定的索引必须是 List 集合的有效索引。例如集合长度为 4,就不能指定替换索引为 4 处的元素,也就是说这个方法不会改变 List 集合的长度。

2.LinkedList 类

  • LinkedList 类采用链表结构保存对象,这种结构的优点是便于向集合中插入或者删除元素。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高,但是 LinkedList 类随机访问元素的速度则相对较慢。这里的随机访问是指检索集合中特定索引位置的元素。

    LinkedList 类除了包含 Collection 接口和 List 接口中的所有方法之外,还特别提供了表 2 所示的方法。

    方法名称 说明
    void addFirst(E e) 将指定元素添加到此集合的开头
    void addLast(E e) 将指定元素添加到此集合的末尾
    E getFirst() 返回此集合的第一个元素
    E getLast() 返回此集合的最后一个元素
    E removeFirst() 删除此集合中的第一个元素
    E removeLast() 删除此集合中的最后一个元素

3.ArrayList 类和 LinkedList 类的区别

  • ArrayList 与 LinkedList 都是 List 接口的实现类,因此都实现了 List 的所有未实现的方法,只是实现的方式有所不同。

    ArrayList 是基于动态数组数据结构的实现,访问元素速度优于 LinkedList。LinkedList 是基于链表数据结构的实现,占用的内存空间比较大,但在批量插入或删除数据时优于 ArrayList。

    对于快速访问对象的需求,使用 ArrayList 实现执行效率上会比较好。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高。

    不同的结构对应于不同的算法,有的考虑节省占用空间,有的考虑提高运行效率,对于程序员而言,它们就像是“熊掌”和“鱼肉”,不可兼得。高运行速度往往是以牺牲空间为代价的,而节省占用空间往往是以牺牲运行速度为代价的。

4.Set集合

1.HashSet 类

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时就是使用这个实现类。HashSet 是按照 Hash 算法来存储集合中的元素。因此具有很好的存取和查找性能。

HashSet 具有以下特点:

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
  • HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。
  • 集合元素值可以是 null。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值决定该对象在 HashSet 中的存储位置。如果有两个元素通过 equals() 方法比较返回的结果为 true,但它们的 hashCode 不相等,HashSet 将会把它们存储在不同的位置,依然可以添加成功。

也就是说,两个对象的 hashCode 值相等且通过 equals() 方法比较返回结果为 true,则 HashSet 集合认为两个元素相等。

在 HashSet 类中实现了 Collection 接口中的所有方法。HashSet 类的常用构造方法重载形式如下。

  • HashSet():构造一个新的空的 Set 集合。
  • HashSet(Collection<? extends E>c):构造一个包含指定 Collection 集合元素的新 Set 集合。其中,“< >”中的 extends 表示 HashSet 的父类,即指明该 Set 集合中存放的集合元素类型。c 表示其中的元素将被存放在此 Set 集合中。

2.TreeSet 类

  • TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序,因此使用 TreeSet 类实现的 Set 接口默认情况下是自然排序的,这里的自然排序指的是升序排序。

    TreeSet 只能对实现了 Comparable 接口的类对象进行排序,因为 Comparable 接口中有一个 compareTo(Object o) 方法用于比较两个对象的大小。例如 a.compareTo(b),如果 a 和 b 相等,则该方法返回 0;如果 a 大于 b,则该方法返回大于 0 的值;如果 a 小于 b,则该方法返回小于 0 的值。

    表 1 列举了 JDK 类库中实现 Comparable 接口的类,以及这些类对象的比较方式。

    比较方式
    包装类(BigDecimal、Biglnteger、 Byte、Double、 Float、Integer、Long 及 Short) 按数字大小比较
    Character 按字符的 Unicode 值的数字大小比较
    String 按字符串中字符的 Unicode 值的数字大小比较

    TreeSet 类除了实现 Collection 接口的所有方法之外,还提供了如表 2 所示的方法。

    方法名称 说明
    E first() 返回此集合中的第一个元素。其中,E 表示集合中元素的数据类型
    E last() 返回此集合中的最后一个元素
    E poolFirst() 获取并移除此集合中的第一个元素
    E poolLast() 获取并移除此集合中的最后一个元素
    SortedSet subSet(E fromElement,E toElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象与 toElement 对象之间的所有对象。包含 fromElement 对象,不包含 toElement 对象
    SortedSet headSet<E toElement〉 返回一个新的集合,新集合包含原集合中 toElement 对象之前的所有对象。 不包含 toElement 对象
    SortedSet tailSet(E fromElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象之后的所有对 象。包含 fromElement 对象

    注意:表面上看起来这些方法很多,其实很简单。因为 TreeSet 中的元素是有序的,所以增加了访问第一个、前一个、后一个、最后一个元素的方法,并提供了 3 个从 TreeSet 中截取子 TreeSet 的方法。

5.Map集合

  • Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键(key)对象和一个值(value)对象。用于保存具有映射关系的数据。

    Map 集合里保存着两组值,一组值用于保存 Map 里的 key,另外一组值用于保存 Map 里的 value,key 和 value 都可以是任何引用类型的数据。Map 的 key 不允许重复,value 可以重复,即同一个 Map 对象的任何两个 key 通过 equals 方法比较总是返回 false。

    Map 中的 key 和 value 之间存在单向一对一关系,即通过指定的 key,总能找到唯一的、确定的 value。从 Map 中取出数据时,只要给出指定的 key,就可以取出对应的 value。

    Map 接口主要有两个实现类:HashMap 类和 TreeMap 类。其中,HashMap 类按哈希算法来存取键对象,而 TreeMap 类可以对键对象进行排序。

    Map 接口中提供的常用方法如表 1 所示。

    方法名称 说明
    void clear() 删除该 Map 对象中的所有 key-value 对。
    boolean containsKey(Object key) 查询 Map 中是否包含指定的 key,如果包含则返回 true。
    boolean containsValue(Object value) 查询 Map 中是否包含一个或多个 value,如果包含则返回 true。
    V get(Object key) 返回 Map 集合中指定键对象所对应的值。V 表示值的数据类型
    V put(K key, V value) 向 Map 集合中添加键-值对,如果当前 Map 中已有一个与该 key 相等的 key-value 对,则新的 key-value 对会覆盖原来的 key-value 对。
    void putAll(Map m) 将指定 Map 中的 key-value 对复制到本 Map 中。
    V remove(Object key) 从 Map 集合中删除 key 对应的键-值对,返回 key 对应的 value,如果该 key 不存在,则返回 null
    boolean remove(Object key, Object value) 这是 Java 8 新增的方法,删除指定 key、value 所对应的 key-value 对。如果从该 Map 中成功地删除该 key-value 对,该方法返回 true,否则返回 false。
    Set entrySet() 返回 Map 集合中所有键-值对的 Set 集合,此 Set 集合中元素的数据类型为 Map.Entry
    Set keySet() 返回 Map 集合中所有键对象的 Set 集合
    boolean isEmpty() 查询该 Map 是否为空(即不包含任何 key-value 对),如果为空则返回 true。
    int size() 返回该 Map 里 key-value 对的个数
    Collection values() 返回该 Map 里所有 value 组成的 Collection

    Map 集合最典型的用法就是成对地添加、删除 key-value 对,接下来即可判断该 Map 中是否包含指定 key,也可以通过 Map 提供的 keySet() 方法获取所有 key 组成的集合,进而遍历 Map 中所有的 key-value 对。

6.遍历map集合的四种方式

  1. 在 for 循环中使用 entries 实现 Map 的遍历(最常见和最常用的)。

    • public static void main(String[] args) {
          Map<String, String> map = new HashMap<String, String>();
          map.put("Java入门教程", "http://c.biancheng.net/java/");
          map.put("C语言入门教程", "http://c.biancheng.net/c/");
          for (Map.Entry<String, String> entry : map.entrySet()) {
              String mapKey = entry.getKey();
              String mapValue = entry.getValue();
              System.out.println(mapKey + ":" + mapValue);
          }
      }
      
  2. 使用 for-each 循环遍历 key 或者 values,一般适用于只需要 Map 中的 key 或者 value 时使用。性能上比 entrySet 较好。

    • Map<String, String> map = new HashMap<String, String>();
      map.put("Java入门教程", "http://c.biancheng.net/java/");
      map.put("C语言入门教程", "http://c.biancheng.net/c/");
      // 打印键集合
      for (String key : map.keySet()) {
          System.out.println(key);
      }
      // 打印值集合
      for (String value : map.values()) {
          System.out.println(value);
      }
      
  3. 使用迭代器(Iterator)遍历。

    • Map<String, String> map = new HashMap<String, String>();
      map.put("Java入门教程", "http://c.biancheng.net/java/");
      map.put("C语言入门教程", "http://c.biancheng.net/c/");
      Iterator<Entry<String, String>> entries = map.entrySet().iterator();
      while (entries.hasNext()) {
          Entry<String, String> entry = entries.next();
          String key = entry.getKey();
          String value = entry.getValue();
          System.out.println(key + ":" + value);
      }
      
  4. 通过键找值遍历,这种方式的效率比较低,因为本身从键取值是耗时的操作。

    • for(String key : map.keySet()){
          String value = map.get(key);
          System.out.println(key+":"+value);
      }
      

7.Iterator(迭代器)

  • Iterator(迭代器)是一个接口,它的作用就是遍历容器的所有元素,也是 Java 集合框架的成员,但它与 Collection 和 Map 系列的集合不一样,Collection 和 Map 系列集合主要用于盛装其他对象,而 Iterator 则主要用于遍历(即迭代访问)Collection 集合中的元素。

    Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口。Iterator 接口里定义了如下 4 个方法。

    • boolean hasNext():如果被迭代的集合元素还没有被遍历完,则返回 true。
    • Object next():返回集合里的下一个元素。
    • void remove():删除集合里上一次 next 方法返回的元素。
    • void forEachRemaining(Consumer action):这是 Java 8 为 Iterator 新增的默认方法,该方法可使用 Lambda 表达式来遍历集合元素。
  • 注意:Iterator 必须依附于 Collection 对象,若有一个 Iterator 对象,则必然有一个与之关联的 Collection 对象。Iterator 提供了两个方法来迭代访问 Collection 集合里的元素,并可通过 remove() 方法来删除集合中上一次 next() 方法返回的集合元素。

  • 当使用 Iterator 迭代访问 Collection 集合元素时,Collection 集合里的元素不能被改变,只有通过 Iterator 的 remove() 方法删除上一次 next() 方法返回的集合元素才可以,否则将会引发“java.util.ConcurrentModificationException”异常。

  • terator 迭代器采用的是快速失败(fail-fast)机制,一旦在迭代过程中检测到该集合已经被修改(通常是程序中的其他线程修改),程序立即引发 ConcurrentModificationException 异常,而不是显示修改后的结果,这样可以避免共享资源而引发的潜在问题。

    快速失败(fail-fast)机制,是 Java Collection 集合中的一种错误检测机制。

8.泛型

  1. 泛型集合

    • 泛型本质上是提供类型的“类型参数”,也就是参数化类型。我们可以为类、接口或方法指定一个类型参数,通过这个参数限制操作的数据类型,从而保证类型转换的绝对安全。
  2. 泛型类

    • 除了可以定义泛型集合之外,还可以直接限定泛型类的类型参数。语法格式如下:

      public class class_name<data_type1,data_type2,…>{}
      

      其中,class_name 表示类的名称,data_ type1 等表示类型参数。Java 泛型支持声明一个以上的类型参数,只需要将类型用逗号隔开即可。

      泛型类一般用于类中的属性类型不确定的情况下。在声明属性时,使用下面的语句:

      private data_type1 property_name1;
      private data_type2 property_name2;
      

      该语句中的 data_type1 与类声明中的 data_type1 表示的是同一种数据类型。

  3. 泛型方法

    • [访问权限修饰符][static][final]<类型参数列表>返回值类型方法名([形式参数列表])
      

      例如:

      public static List<T> find(Class<T>class,int userId){}
      

      一般来说编写 Java 泛型方法,其返回值类型至少有一个参数类型应该是泛型,而且类型应该是一致的,如果只有返回值类型或参数类型之一使用了泛型,那么这个泛型方法的使用就被限制了。

  4. 泛型高级用法

    1. 限制泛型可用类型

      • 在 Java 中默认可以使用任何类型来实例化一个泛型类对象。当然也可以对泛型类实例的类型进行限制,语法格式如下:

        class 类名称<T extends anyClass>
        

        其中,anyClass 指某个接口或类。使用泛型限制后,泛型类的类型必须实现或继承 anyClass 这个接口或类。无论 anyClass 是接口还是类,在进行泛型限制时都必须使用 extends 关键字。

    2. 使用类型通配符

      • Java 中的泛型还支持使用类型通配符,它的作用是在创建一个泛型类对象时限制这个泛型类的类型必须实现或继承某个接口或类。

        使用泛型类型通配符的语法格式如下:

        泛型类名称<? extends List>a = null;
        

        其中,“<? extends List>”作为一个整体表示类型未知,当需要使用泛型对象时,可以单独实例化。

    3. 继承泛型类和实现泛型接口

      • 定义为泛型的类和接口也可以被继承和实现。例如下面的示例代码演示了如何继承泛型类。

        public class FatherClass<T1>{}
        public class SonClass<T1,T2,T3> extents FatherClass<T1>{}
        

        如果要在 SonClass 类继承 FatherClass 类时保留父类的泛型类型,需要在继承时指定,否则直接使用 extends FatherClass 语句进行继承操作,此时 T1、T2 和 T3 都会自动变为 Object,所以一般情况下都将父类的泛型类型保留。

9.枚举

  1. 声明枚举

    • 声明枚举时必须使用 enum 关键字,然后定义枚举的名称、可访问性、基础类型和成员等。枚举声明的语法如下:

      enum-modifiers enum enumname:enum-base {
          enum-body,
      }
      

      其中,enum-modifiers 表示枚举的修饰符主要包括 public、private 和 internal;enumname 表示声明的枚举名称;enum-base 表示基础类型;enum-body 表示枚举的成员,它是枚举类型的命名常数。

      任意两个枚举成员不能具有相同的名称,且它的常数值必须在该枚举的基础类型的范围之内,多个枚举成员之间使用逗号分隔。

      提示:如果没有显式地声明基础类型的枚举,那么意味着它所对应的基础类型是 int。

  2. 枚举类

    • ava 中的每一个枚举都继承自 java.lang.Enum 类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可。

      所有枚举实例都可以调用 Enum 类的方法,常用方法如表 1 所示。

      方法名称 描述
      values() 以数组形式返回枚举类型的所有成员
      valueOf() 将普通字符串转换为枚举实例
      compareTo() 比较两个枚举成员在定义时的顺序
      ordinal() 获取枚举成员的索引位置
  3. EnumMap类

    • EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其他的 Map(如 HashMap)实现也能完成枚举类型实例到值的映射,但是使用 EnumMap 会更加高效。

      HashMap 只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值,使得 EnumMap 的效率非常高。

  4. EnumSet类

    • EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。EnumSet 提供了许多工厂方法以便于初始化,如表 2 所示。

      方法名称 描述
      allOf(Class element type) 创建一个包含指定枚举类型中所有枚举成员的 EnumSet 对象
      complementOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并包含所有 s 中未包含的枚举成员
      copyOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并与 s 包含相同的枚举成员
      noneOf(<Class elementType) 创建指定枚举类型的空 EnumSet 对象
      of(E first,e...rest) 创建包含指定枚举成员的 EnumSet 对象
      range(E from ,E to) 创建一个 EnumSet 对象,该对象包含了 from 到 to 之间的所有枚 举成员

接下来看java基础学习(七)

java基础学习(六)

原文:https://www.cnblogs.com/namusangga/p/14613672.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!