java常用类+异常+常用工具类

目录

 

一、常用类

1、包装类

2、字符串相关:String、StringBuffer、StringBuilder(重要)

1、String:

2、StringBuilder 内部可变数组,存在初始化StringBuilder对象中字符数组容量为16,存在扩容。(所以后面需要去看看其扩容机制)

3、StringBuffer

总结:

3、时间处理相关类

常用方法

 示例

4、枚举类

5、Math、Random等类

6、File类

二、异常

1、异常分类

2、异常处理

3、自定义异常

4、

三、常用的工具类


一、常用类

1、包装类

Java语言是一个面向对象的语言,但是Java中的基本数据类型却 是不面向对象的。但是我们在实际使用中经常需要将基本数据转化成对象,便于操作。比如: 集合的操作中。 这时,我们就需要将基本类型数据转化成对象!

包装类均位于java.lang包,包装类和基本数据类型的对应关系:

• 自动装箱-boxing

        • 基本类型就自动地封装到与它相同类型的包装中,如:

        • Integer i = 100;

        • 本质上是,编译器编译时为我们添加了:

        • Integer i = Integer.valueOf(100);

• 自动拆箱autounboxing

        • 包装类对象自动转换成基本类型数据。如:

        • int a = new Integer(100);

        • 本质上,编译器编译时为我们添加了:

        • int a = new Integer(100).intValue(); 

2、字符串相关:String、StringBuffer、StringBuilder(重要)

先从这三个的主要特性说起

• String:不可变字符序列 (初始容量看自己初始的长度)

• StringBuilder:可变字符序列、效率高、线程不安全(初始长度是16,可以扩容) 

• StringBuffer:可变字符序列、效率低、线程安全

接下来提问,为什么String是不可变字符序列而其他两个是可变的? 为什么效率StringBuilder>String>StringBuffer?为什么StringBuffer线程安全,其他两个不安全?在工作中为什么业务层频繁的拼接sql不用string而用StringBuilder?这些问题都从三个类的源码解析:

1、String:

       我们知道字符串其实就是由若干个字符线性排列而成的,可以理解为字符数组Array,那么既然是数组实现的,那就需要考虑到数组的特性,数组在内存中是一块连续的地址空间块,即在定义数组的时候需要指定数组的大小

    换言之, 数组就分为可变数组和不可变数组。可变数组能够动态插入和删除,而不可变数组一旦分配好空间后则不能进行动态插入或删除操作。

    在实际的字符串应用场景中,涉及到多种操作,比如字符串的插入,删除,修改,拼接,查询,替换...(这一些String源码是如何实现的?)

       String为不可变类,属性value为不可变数组,即String初始化构造器没有初始容量为16的概念,你定义多少,String中字符数组的长度就是多少,不存在字符数组扩容一说。看下源码:

//String类使用final修饰,且其值value[]也是用final修饰
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];
    private int hash; // Default to 0

     public String() {      
        this.value = new char[0];
    }

    public String(String original) {   
        this.value = original.value;
        this.hash = original.hash;
    }
        
    public String(char value[]) { //此时是浅拷贝(前面知识点有提到),将真实值/长度拷贝给value
                                  //浅拷贝转深拷贝的方法是重写拷贝方法/序列化,而String继承了 
                                  //serializable(序列化),所以算是转成了深拷贝??
                                  //copyof是复制指定的数组,如果长度超过了会先用空值占位
        this.value = Arrays.copyOf(value, value.length);
    }    
    
    ...
}

可以看出String和其值value都是被final修饰的,即value只能初始化一次。所以当给String赋值后就不能改变其值了,也就是所说的String是不可变的。这时提问,既然不可变为什么可以对String做一些截取字符串插入删除等操作?

这里以String截取方法subString()为例:

/**
      返回一个字符串开始索引是从 0 开始 到 endIndex - 1
      这个字符串的长度是  endIndex - beginIndex
     */
    public String substring(int beginIndex, int endIndex) {
       //开始索引 < 0 抛异常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //结束索引 > 字符数组长度 抛异常
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        //子字符串长度
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
        //这3个参数 依次为字符数组,  开始索引,    数组长度==
l   }
    

return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);

解析:如果开始索引为0且结束索引为数组长度(即截取整个字符串)则返回this本身字符串,

          否则执行new String(value, beginIndex, subLen),即再new了一个String对象存储要截取的字符串。

再以String的替换的方法replace方法为例:

//替换方法,将older字符全部替换为newChar
public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = value.length;
        int i = -1;
        char[] val = value; 

        while (++i < len) {
            if (val[i] == oldChar) {
                break;
            }
        }
        if (i < len) {
            char buf[] = new char[len];
            for (int j = 0; j < i; j++) {
                buf[j] = val[j];    //原理是创建新数组,全部复制过去
            }
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;
                i++;
            }
            return new String(buf, true);  //原理还是重新new 一个String对象
        }
    }
    return this;
}

return new String(buf, true);  //原理还是重新new 一个String对象,这也就是为什么我们如果采用String对象频繁的进行拼接,截取,替换操作效率很低下的原因

注意点:String有一个概念就是常量池,即每次创建字符串时会先去常量池看是否有已经存在了的字符串,有则直接使用而不再去创建了,如没有则会创建并将其放入到常量池中供别人使用。

举例:

String s = we+lcometo360”;只创建了一个对象

全是常量的字符串在编译时会进行优化,也就是说编译器会将你写的语句优化成String s = “welcometo360”

String s = “aa” s=s+“cc”   创建了两个
不是全常量则先创建一个s指向aa;第二句则再创建一个指向aacc;(第二句可以看成s=aa+cc,则优化为aacc,而String s是不能改变的,所以内存会再创建一个对象存储aacc再指向给s)
String b = new String(”aaa“);创建了两个对象,一个是aaa,一个是new创建的对象b,b指向的是new处理的地址,该地址再指向常量池的aaa(aaa在创建后会放入常量池)
此时在看 String c =”aaa“; 请问==是相等的吗?
答案是flase,因为b的指向是:b-->new的地址-->常量池的aaa;而c的指向是:c--->常量池的aaa,所以b和c的指向不同则为flase
右边运算只有单纯的字符串则会在编译时优化为其最终的结果;如不是单纯的字符串还存在String对象则是先去找对象的值再和单纯的字符串相加再new一个String对象指向这些结果(即右边有对象时是new一个新对象,单纯字符串则是去常量池找)。

下面列举一些String常用的方法:

  • equals:字符串是否相同
  • equalsIgnoreCase:忽略大小写后字符串是否相同
  • compareTo:根据字符串中每个字符的Unicode编码进行比较
  • compareToIgnoreCase:根据字符串中每个字符的Unicode编码进行忽略大小写比较
  • indexOf:目标字符或字符串在源字符串中位置下标
  • lastIndexOf:目标字符或字符串在源字符串中最后一次出现的位置下标
  • valueOf:其他类型转字符串
  • charAt:获取指定下标位置的字符
  • codePointAt:指定下标的字符的Unicode编码
  • concat:追加字符串到当前字符串
  • isEmpty:字符串长度是否为0
  • contains:是否包含目标字符串
  • startsWith:是否以目标字符串开头
  • endsWith:是否以目标字符串结束
  • format:格式化字符串
  • getBytes:获取字符串的字节数组
  • getChars:获取字符串的指定长度字符数组
  • toCharArray:获取字符串的字符数组
  • join:以某字符串,连接某字符串数组
  • length:字符串字符数
  • matches:字符串是否匹配正则表达式
  • replace:字符串替换
  • replaceAll:带正则字符串替换
  • replaceFirst:替换第一个出现的目标字符串
  • split:以某正则表达式分割字符串
  • substring:截取字符串
  • toLowerCase:字符串转小写
  • toUpperCase:字符串转大写
  • trim:去字符串首尾空格

而对于为什么其他两个是可变的,简单点说,他们的value是用变量的所以是可变的,而String是用常量是不可变的,下面来解析StringBuilder源码:

2、StringBuilder
 内部可变数组,存在初始化StringBuilder对象中字符数组容量为16,存在扩容。(所以后面需要去看看其扩容机制)

StringBuilder类继承AbstractStringBuilder抽象类,其中StringBuilder的大部分方法都是直接调用的父类的实现。

再看下StringBuilder的几个构造函数

1、无参:

可以看出是调用父类的无参构造函数,而父类的无参构造函数默认字符数组的长度为16

2、自定义长度构造函数(int)

3、以字符串String 作为参数的构造

在参数Str 数组长度的基础上再增加16个字符长度,作为StringBuilder实例的初始数组容量,并将str字符串 append到StringBuilder的数组中。此时来解析下StringBuilder的append方法,其可变性也可以从append的原理分析

4、append方法:

StringBuilder的方法也是调用父类AbstractStringBuilder的append方法,所以直接看父类的append方法

主要逻辑:1、如果进来的str为null,执行sppendNull方法,否则

                  2、获取str长度

                  3、申请扩容(原先的count加上传进来的str的长度)

                   4、获取str的字符数组

                   5、将StringBuilder的长度改为count+str.length

                   6、将扩容完并将str append上去的StringBuilder返回回去

下面详解各个里面各个方法的代码:

     1、进去appendNull()方法:(这里要注意null和 ”“ 的区别,其中null在String中是一个n+u+l+l的字符数组,”“才是没有字符,所以此时进去appendNull的实际是null的字符数组。)该方法的主要逻辑:先获取当前字符的长度count,然后加上null四个字符,调用ensureCapacityInternal()扩容方法再扩容四个空间,然后把null四个字符加到扩容后的value数组中去,然后记录扩容后的count并返回最后的字符数组

再进去扩容方法ensureCapacityInternal()看看扩容机制的原理:从下面的代码可以看出,传进去原长度+追加长度,此时先判断如果传进去的值大于字符数组的值则进行扩容,此时是调用Arrays类的copyOf()方法(即实际的扩容机制是利用Arrays的copyOf方法进行扩容)()

   为了进一步了解copyOf方法是怎么扩容的,

  • copyOf():复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度
  • 即copyOf(原先的字符数组,扩容后的总长度),此时该字符数组则只是 原先字符数组+多个空值填充

(该空值填充是为后面追加上来的字符数组占位,即此时追加的字符数组还没有真正的实现追加)

此时就剩最后一个方法:即str.getChars(追加字符串的起始索引,要追加的字符串结尾索引,原先字符数组,原字符数组长度)

注意:这里由于是StringBuilder调用的append,所有该value指的是原先字符数组。

此时进去getChars方法看是如何进行字符数组的追加的:

直接进去System的arraycopy方法此时传进的值是(追加字符数组,追加字符串的起始索引,原先的字符数组,原字符数组长度,追加结尾-追加开始的索引(即是追加长度))

注意:这里的value和上面的value不一样,这里是调用追加字符数组的getChars方法,所以其中的value是指追加字符数组

最后通过arraycopy的方法将追加字符数组加了上去。

最后再看下其重写的toString方法

这里的toString方法直接new 一个String对象,将StringBuilder对象的value进行一个拷贝,重新生成一个对象,不共享之前StringBuilder的char[]

总结:即整个StringBuilder的append方法,本质上是调用System的native方法(即数组扩容),直接将String 类型的str字符串中的字符数组,拷贝到了StringBuilder的扩容了的字符数组中

这里注意的是:StringBuilder的底层的扩容机制是扩容“原本长度+新增长度”,所以该扩容机制是比较保守的,由于默认的初始长度是16,所以经常的append会出现每次append一次就扩容一次,就会频繁调用数组拷贝(arraycopy虽然是native方法,效率很快)造成拖低效率。如果频繁要append则可以考虑下将初始值16改大一点从而增大效率。

此时则可以看出:效率:StringBuidler>String:String每次删改等都是要重新new一个String对象,而StringBuilder最多就是调用一下数组拷贝方法,所以StringBuilder的删改效率要远大于String。而可不可变的问题是一个是常量一个是变量。

(数组是线性存储,所以其值在内存中是连续存储的(因为是线性的所以在查询方面效率高),而String/StringBuilder是char[]实现的。)

StringBuilder常用方法

一、创建Stringbuilder对象
StringBuilder strB = new StringBuilder();

1、append(String str)/append(Char c):字符串连接
System.out.println("StringBuilder:"+strB.append("ch").append("111").append('c'));
//return "StringBuilder:ch111c"

2、toString():返回一个与构建起或缓冲器内容相同的字符串
System.out.println("String:"+strB.toString());
//return "String:ch111c"

3、appendcodePoint(int cp):追加一个代码点,并将其转换为一个或两个代码单元并返回this
System.out.println("StringBuilder.appendCodePoint:"+strB.appendCodePoint(2));
//return "StringBuilder.appendCodePoint:ch111c"

4、setCharAt(int i, char c):将第 i 个代码单元设置为 c(可以理解为替换)char字符使用  ‘   ’
strB.setCharAt(2, 'd');
System.out.println("StringBuilder.setCharAt:" + strB);
//return "StringBuilder.setCharAt:chd11c"

5、insert(int offset, String str)/insert(int offset, Char c):在指定位置之前插入字符(串)
System.out.println("StringBuilder.insertString:"+ strB.insert(2, "LS"));
//return "StringBuilder.insertString:chLSd11c"
System.out.println("StringBuilder.insertChar:"+ strB.insert(2, 'L'));
//return "StringBuilder.insertChar:chLLSd11c"

6、delete(int startIndex,int endIndex):删除起始位置(含)到结尾位置(不含)之间的字符串
System.out.println("StringBuilder.delete:"+ strB.delete(2, 4));
//return "StringBuilder.delete:chSd11c"

7、.CharAt(int Index):检索特定索引下的字符

3、StringBuffer

 线程安全的高效字符串操作类,看下源码:(类图、构造函数和StringBuidler一样)

下面直接进去append方法:这里发现append多了一个synchronized(即锁),这里的同步锁则保证了StringBuffer的线程安全,所以说StringBuffer是线程安全的(但这也使其效率变低了)

处了加了锁,StringBuffer和StringBuidler还要一个区别是StringBuffer多了一个参数

这里的作用简单介绍一下,就是去缓存toString的

可以看下StringBuffer的toString方法

这里的作用就是如果StringBuffer对象此时存在toStringCache,在多次调用其toString方法时,其new出来的String对象是会共享同一个char[] 内存的,达到共享的目的。但是StringBuffer只要做了修改,其toStringCache属性值都会置null处理(则需要再次存进改了的值)。这也是StringBuffer和StringBuilder的一个区别点。

StringBuffer常用方法:

StringBuffer sb = new StringBuffer("Hello ");

sb.append("world");   //在sb尾部追加一个字符串, 此时变成 Hello world;

sb.charAt(1) ;  //返回下标为1的字符 此处是 e

sb.insert(1,"d");  //在 1 处插入新的字符串 d  此时变为 Hedllo world;

sb.reverse();  //反转字符 此时变成    dlrow olldeH

sb.delete(1,2);  //删除字符串  此时变为Hllo world

sb.replace(3,4,"new");  //替换字符串  从 3开始到4结束  此时变为  Hllnewworld

StringBuffer<String<StringBuilder 是因为StringBuffer用了锁机制严重的影响其性能,而String是因为每次都new一个对象所以性能也造成影响。但是StringBuffer的优点是线程安全和可变,StringBuilder是可变和效率高。

4、在工作中为什么业务层频繁的拼接sql不用string而用StringBuilder?

不用多说,StringBuilder拼接的效率比String高。原因看上面分析

总结:

    String 类不可变,内部维护的char[] 数组长度不可变,为final修饰,String类也是final修饰,不存在扩容。字符串拼接,截取,都会生成一个新的对象。频繁操作字符串效率低下,因为每次都会生成新的对象。

    StringBuilder 类内部维护可变长度char[] , 初始化数组容量为16,存在扩容, 其append拼接字符串方法内部调用System的native方法,进行数组的拷贝,不会重新生成新的StringBuilder对象。非线程安全的字符串操作类, 其每次调用 toString方法而重新生成的String对象,不会共享StringBuilder对象内部的char[],会进行一次char[]的copy操作。

    StringBuffer 类内部维护可变长度char[], 基本上与StringBuilder一致,但其为线程安全的字符串操作类,大部分方法都采用了Synchronized关键字修改,以此来实现在多线程下的操作字符串的安全性。其toString方法而重新生成的String对象,会共享StringBuffer对象中的toStringCache属性(char[]),但是每次的StringBuffer对象修改,都会置null该属性值。

3、时间处理相关类

1、Date类

  • 以当前时间创建对象
    Date()
  • 以指定纪元时间创建对象
    Date(long date)
  • 常用方法

  • 判断时间点的先后
    boolean  after(Date when)
    boolean  before(Date when)
  • 获取或设置纪元时间
    long  getTime()
    void  setTime(long time)
  •  示例

    Date date = new Date(1420000000000l);  // 纪元毫秒时间转换日期对象

    long millisTime = date.getTime();  // 日期对象转换纪元毫秒时间

2、Calendar类

1). 概述

  • Calendar类是个日历表示法的抽象类,可以通过其静态方法获取当前时间日期的对象
  • Calendar类维护了非常多的字段,可以提供关于日历的各种信息以及转换方法。
  • 实际上,通过静态方法获得的Calendar对象为其子类GregorianCalendar对象,所以也可以直接创建其子类对象进行处理。

2). 常用字段

  • 年,月,日
    YEAR,MONTH,DAY_OF_MONTH/DATE
  • 时,分,秒,毫秒
    HOUR_OF_DAY,MINUTE,SECOND,MILLISECOND
  • 本周星期几,本年第几天,本月第几周,本月第几个7天,本年第几周
    DAY_OF_WEEK,DAY_OF_YEAR,WEEK_OF_YEAR,DAY_OF_WEEK_IN_MONTH,WEEK_OF_YEAR
  • 公元,上下午
    ERA,AM_PM
  • 12小时计时
    HOUR
  • 星期(DAY_OF_WEEK取值范围)
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY
  • 月份(MONTH取值范围,其中JANUARY为0)
    JANUARY,FEBRUARY,MARCH,APRIL,MAY,JUNE,JULY,AUGUST,SEPTEMBER,OCTOBER,NOVEMBER,DECEMBER

3). 常用方法

  • 使用当前日期时间以及默认时区本地化获取日历对象
    static Calendar  getInstance();
  • 获取/设置当前日历的时间
    Date  getTime()
    void  setTime(Date date)
  • 按毫秒单位时间设置日历时间
    void  setTimeInMillis(long millis)
  • 获取指定字段的值
    int  get(int field)
  • 更改指定字段的值
    void  set(int field, int value);
    void  set(int year, int month, int date)
    void  set(int year, int month, int date, int hourOfDay, int minute)
    void  set(int year, int month, int date, int hourOfDay, int minute, int second)
  • 按给定的偏移更改当前日期时间
    abstract void  add(int field, int amount)
  • 获取该日期指定字段的最大值或最小。
    int  getActualMaximum(int field)
    int  getActualMinimum(int field)
  • 获取/设置每周第一天是星期几
    int  getFirstDayOfWeek()
    void  setFirstDayOfWeek(int value)

4). 示例

  1. Calendar cal = Calendar.getInstance();  // 以当前日期时间初始化日历  
  2. cal.set(Calendar.MONTH, Calendar.DECEMBER);  // 设置日历为十一月  
  3. int month = cal .get(Calendar.MONTH);  // 获取日信息  
  4. int maxMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH); // 获取当前日期月的天数。  
  5. System.out.println( "月:" + (month + 1) + "\n该月天数" + maxMonth); 

5)子类:GregorianCalendar类:

  • 可以直接new该类对象完成日历功能的使用。
  • GregorianCalendar类扩展了Calendar类的功能,可以直接通过年月日时分秒的方式创建对象。
    GregorianCalendar()
    GregorianCalendar(int year, int month, int dayOfMonth)
    GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute)
    GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second)
  • GregorianCalendar类提供了世界上大多数历法表示方法。
  • GregorianCalendar类提供了判断闰年的方法
    boolean  isLeapYear(int year)

3、DateFormat类

1). 概述

  • FormateDemo类,该类为抽象类,但是提供了Instance方法可以实现标准样式的格式化和解析。
  • 和Calendar类类似,如需要自定义样式可以使用其子类SimpleDateFormat。

2). 字段

  • SHORT    yy-M-d 上午/下午h:mm
  • MEDIUM   yyyy-M-d h:mm:ss
  • LONG     yyyy年M月d日 上午/下午hh时mm分ss秒
  • FULL     yyyy年M月d日 星期 上午/下午hh时mm分ss秒 CST

3). 方法

  • 按指定标准样式初始化DateFormat对象
    static DateFormat    getInstance();           // 默认风格SHORT
    static DateFormat    getDateInstance();       // 默认风格MEDIUM
    static DateFormat    getTimeInstance();       // 默认风格MEDIUM
    static DateFormat    getDateTimeInstance();   // 默认风格MEDIUM
  • 将日期对象按指定标准样式转化为字符串
    String    format(Date date);
  • 将字符串按指定标准样式解析为日期对象
    Date    parse(String source);

4). 示例

  1. Date date = new Date(1391234567891l);  
    // 指定标准样式  
    DateFormat dateStaFormat = DateFormat.getDateTimeInstance(DateFormat. LONG, DateFormat.MEDIUM );  
    String date_Sta_str = dateStaFormat.format(date ); // 格式化,2014年2月1日 14:02:47  
       
    String dateTime = "2014年11月15日 14:16:50";  
    try {  
      Date nowDateTime = dateStaFormat.parse(dateTime ); // 解析,Sat Nov 15 14:16:50 CST 2014  
      long millisTime = nowDateTime.getTime(); // 1416032210000  
    } catch (ParseException e) {  
      e.printStackTrace();  
    }  

子类:SimpleDateFormat类

1). 概述

  • SimpleDateFormat类是DateFormat的子类,和Calendar类似,DateFormat类通过工厂方法获得的对象就是SimpleDateFormat类对象。
  • SimpleDateFormat类可以按指定样式创建对象,可以自定义日期时间的格式。

2). 日期和时间模式

其中,未加''的字母将被识别为模式,所以非匹配字母需要加''以示区分。

3). 构造器

SimpleDateFormat()
SimpleDateFormat(String pattern)
SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
SimpleDateFormat(String pattern, Locale locale)

4). 常用方法

更换指定样式
void  applyPattern(String pattern)

5). 示例

Date date = new Date(1391234567891l);  
// 指定样式  
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd 'at' HH:mm:ss.SSS" );  
String date_str = dateFormat.format( date);  // 格式化,2014/02/01 at 14:02:47.891  
   
dateFormat.applyPattern("yyyy.MM.dd" );  // 更换样式  
String dateTime = "2014.11.15";  
try {  
  Date nowDateTime = dateFormat.parse( dateTime); // 解析,Sat Nov 15 00:00:00 CST 2014  
} catch (ParseException e) {  
  e.printStackTrace();  
}  

总结:

Date,Calendar和DateFormat的关系

1. Date和Calendar可以相互转换。

2. Date和DateFormat配合格式化和解析。

3. 也就是说Date可以作为桥梁存在。

4. 示例

package date;  
   
import java.text.DateFormat;  
import java.text.ParseException;  
import java.util.Calendar;  
import java.util.Date;  
   
   
public class GregorianCalendarDemo {  
   
  public static void main(String[] args) throws ParseException {  
    Date date = new Date();  
    Calendar cal = Calendar.getInstance();  
    DateFormat df = DateFormat.getInstance();  
     
    // 1. Date <-> Calendar  
    Calendar date2cal = Calendar.getInstance();  
    date2cal.setTime( date);  
    Date cal2date = cal.getTime();  
     
    // 2. Date <-> DateFormat  
    String time = df.format(date); // "14-12-16 下午11:47"  
    Date df2date = df.parse( time); // Tue Dec 16 23:48:00 CST 2014  
  }  
}  

4、枚举类

• 只能够取特定值中的一个

• 使用enum关键字

• 所有的枚举类型隐性地继承自 java.lang.Enum。(枚举实质上还是类!而每个被枚举的成 员实质就是一个枚举类型的实例,他们默认都是public static final的。可以直接通过枚举 类型名直接使用它们。)

• 强烈建议当你需要定义一组常量时,使用枚举类型

• 尽量不要使用枚举的高级特性,事实上高级特性都可以使用普通类来实现,没有必要引 入复杂性!

5、Math、Random等类

• 包含了常见的数学运算函数。

• random() 生成[0,1)之间的随机浮点数

• 生成:0-10之间的任意整数:

• int a = (int)(10*Math.random());

• 生成:20-30之间的任意整数:

• int b = 20 + (int)(10*Math.random());

6、File类

• 文件和目录路径名的抽象表示形式。一个File对象可以代表一个文件或目录

• 可以实现获取文件和目录属性等功能

• 可以实现对文件和目录的创建、删除等功能

• File不能访问文件内容 File file = new File("d:\\test\\java.txt"); File file = new File("d:/test/java.txt"); File file = new File("java.txt"); 路径可以是绝对路径和相对路径,分隔符采用\\或者/ SSXXT File类

• 通过File对象可以访问文件的属性。

public String getName()

public String getPath()

public boolean isFile()

public boolean isDirectory()

public boolean canRead()

public boolean canWrite()

public boolean exists()

public long length()

public boolean isHidden()

public long lastModified()

public File [] listFiles();

• 通过File对象创建空文件或目录(在该对象所指的文件或目录不存在的情况下)。

• public boolean createNewFile()throws IOException

• public boolean delete()

• public boolean mkdir(), mkdirs() 注意两个的区别!!

(File只是代表一个文件/目录,并不能访问/修改文件内容,修改文件内容需要用流来修改)

二、异常

1、异常分类

• Error (运行时无法控制的错误)

    • Error类层次描述了Java运行时系统内部错误和资源耗尽错误,一般指与JVM或动态加载等相关的 问题,如虚拟机错误,动态链接失败,系统崩溃等。
    • 这类错误是我们无法控制的,同时也是非常罕见的错误。所以在编程中,不去处理这类错误。
    • 打开JDK包:java.lang.Error,查看他的所有子类
    • 注:我们不需要管理Error!

• Exception (异常,可进行异常捕获等)

    • 所有异常类的父类,其子类对应了各种各样可能出现的异常事件。

    • Exception分类

       1) • 运行时异常Runtime Exception(unchecked Exception)

                • 可不必对其处理,系统自动检测处理 • 一类特殊的异常,如被 0 除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显式的声 明或捕获将会对程序可读性和运行效率影响很大

        2)• 检查异常 Checked  Exception

                • 必须捕获进行处理,否则会出现编译错误
• 注意:只有Java提供了Checked异常,体现了Java的严谨性,提高了Java的健壮性。同时也是一个 备受争议的问题。

2、异常处理

一、try-catch、try-catch-finally、try-finally (catch和finally不能同时没有)

Finally一定执行即使catch中有return还是要执行finally的代码。

catch和finally存在return的问题?当catch/try中有return是,我们知道finally的值一定要执行,那finally的代码会不会影响到catch/try中return 的值/对象?

1、不管有木有出现异常,finally块中代码都会执行;
2、当trycatch中有return时,finally仍然会执行;
3finally是在catch/tryz中return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;(如果return的是对象,finally对对象的内容改变,则返回的对象内容是有改变的)
4finally中最好不要包含return,否则程序会提前退出,返回值不是trycatch中保存的返回值。

例:

如果catch/try中有return a;   //此时会先执行a,并将a先保存起来,然后再去执行finally的代码

finally{代码对a进行改变}      //此时分两种情况,1、如果a是基本数据类型,则不会改变保存了的a的值,、

                                            //2、如果a是引用类型,如果修改a指向的内容还是会改变a的内容的。(a为引用类型时传递的是地址,我们改不了地址则可以改变地址指向的内容)

                                           //另外finally还存在是否有return的清理,有return时会直接执行,提前退出,此时返回的不是之前catch/try中保存的值,而是finally中return的值,所以一般不推荐在finally写return,finally一般是用来关闭流等

try中也可以自己手动抛出异常throw:

• 手动抛出异常throw

    • Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要手工创建 并抛出。
    • 在捕获一个异常前,必须有一段代码先生成异常对象并把它抛出。这个过程我们可以手工做, 也可以由JRE来实现,但是他们调用的都是throw子句。
    • 注意抛出运行时异常和Checked异常的区别

        • 抛出Checked异常,该throw语句要么处于try块中,要么方法签名中石油throws抛出

        • 抛出运行时异常,没有以上要求

二、throws

• 声明异常throws

    • 当Checked Exception产生时,不一定立刻处理它,可以再把异常Throws出去
    • 如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开
• 子类声明的异常范围不能超过父类声明范围

    • 父类没有声明异常,子类也不能

    • 不可抛出原有方法抛出异常类的父类或上层类 

3、自定义异常

• 在程序中,可能会遇到任何标准异常类都没有充分的描述清楚的问题,这种情况下可以 创建自己的异常类
• 从Exception类或者它的子类派生一个子类即可 
• 习惯上,定义的类应该包含2个构造器:一个是默认构造器,另一个是带有详细信息的 构造器

4、

运行时异常是jvm自己检查的所以不是一定要trycatch(程序员不知是否有运行时异常),编译时发现异常就必须要加上trycatch/throws

注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。

通常,Java的异常(包括Exception和Error)分为 可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)
可查异常(编译器要求必须处置的异常): 正确的程序在运行中,很容易出现的、情理可容的异常状况 。 可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常 状况,就必须采取某种方式进行处理。

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。

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

运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

非运行时异常 (编译异常): 是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常

对于try、catch、finally进行各种情况详细分析:
在try语句块或catch语句块中执行到System.exit(0)直接退出程序  System.exit(0)。表示将整个虚拟机里的内容都释放,JVM停止工作,此时程序正常退出;
结论:
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;(如果return的是对象,finally对对象的内容改变,则返回的对象内容是有改变的)
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
举例:

情况1:try{} catch(){}finally{} return;
显然程序按顺序执行

情况2:try{ return; }catch(){} finally{} return;
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,最后执行try中return;
finally块之后的语句return,因为程序在try中已经return所以不再执行。

情况3:try{ } catch(){return;} finally{} return;
程序先执行try,如果遇到异常执行catch块,
有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
最后执行catch块中return. finally之后也就是4处的代码不再执行。
无异常:执行完try再finally再return.

情况4:try{ return; }catch(){} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。

情况5:try{} catch(){return;}finally{return;}
程序执行catch块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。

情况6:try{ return;}catch(){return;} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;
有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
则再执行finally块,因为finally块中有return所以提前退出。
无异常:则再执行finally块,因为finally块中有return所以提前退出。

最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
编译器把finally中的return实现为一个warning。

三、常用的工具类

在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类。

1 org.apache.commons.io.IOUtils

closeQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块
toString:转换IO流、 Uri、 byte[]为String
copy:IO流数据复制,从输入流写到输出流中,最大支持2GB
toByteArray:从输入流、URI获取byte[]
write:把字节. 字符等写入输出流
toInputStream:把字符转换为输入流
readLines:从输入流中读取多行数据,返回List<String>
copyLarge:同copy,支持2GB以上数据的复制
lineIterator:从输入流返回一个迭代器,根据参数要求读取的数据量,全部读取,如果数据不够,则失败

2 org.apache.commons.io.FileUtils

deleteDirectory:删除文件夹
readFileToString:以字符形式读取文件内容
deleteQueitly:删除文件或文件夹且不会抛出异常
copyFile:复制文件
writeStringToFile:把字符写到目标文件,如果文件不存在,则创建
forceMkdir:强制创建文件夹,如果该文件夹父级目录不存在,则创建父级
write:把字符写到指定文件中
listFiles:列举某个目录下的文件(根据过滤器)
copyDirectory:复制文件夹
forceDelete:强制删除文件

3 org.apache.commons.lang.StringUtils

isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符
split:分割字符串
EMPTY:返回空字符串
trimToNull:trim后为空字符串则转换为null
replace:替换字符串

4 org.apache.http.util.EntityUtils

toString:把Entity转换为字符串
consume:确保Entity中的内容全部被消费。可以看到源码里又一次消费了Entity的内容,假如用户没有消费,那调用Entity时候将会把它消费掉
toByteArray:把Entity转换为字节流
consumeQuietly:和consume一样,但不抛异常
getContentCharset:获取内容的编码

5 org.apache.commons.lang3.StringUtils

isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符
split:分割字符串
EMPTY:返回空字符串
replace:替换字符串
capitalize:首字符大写

6 org.apache.commons.io.FilenameUtils

getExtension:返回文件后缀名
getBaseName:返回文件名,不包含后缀名
getName:返回文件全名
concat:按命令行风格组合文件路径(详见方法注释)
removeExtension:删除后缀名
normalize:使路径正常化
wildcardMatch:匹配通配符
seperatorToUnix:路径分隔符改成unix系统格式的,即/
getFullPath:获取文件路径,不包括文件名
isExtension:检查文件后缀名是不是传入参数(List<String>)中的一个

7 org.springframework.util.StringUtils

hasText:检查字符串中是否包含文本
hasLength:检测字符串是否长度大于0
isEmpty:检测字符串是否为空(若传入为对象,则判断对象是否为null)
commaDelimitedStringToArray:逗号分隔的String转换为数组
collectionToDelimitedString:把集合转为CSV格式字符串
replace 替换字符串
delimitedListToStringArray:相当于split
uncapitalize:首字母小写
collectionToDelimitedCommaString:把集合转为CSV格式字符串
tokenizeToStringArray:和split基本一样,但能自动去掉空白的单词

8 org.apache.commons.lang.ArrayUtils

contains:是否包含某字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组

9 org.apache.commons.lang.StringEscapeUtils

参考十五:org.apache.commons.lang3.StringEscapeUtils

10 org.apache.http.client.utils.URLEncodedUtils

format:格式化参数,返回一个HTTP POST或者HTTP PUT可用application/x-www-form-urlencoded字符串
parse:把String或者URI等转换为List<NameValuePair>

11 org.apache.commons.codec.digest.DigestUtils

md5Hex:MD5加密,返回32位字符串
sha1Hex:SHA-1加密
sha256Hex:SHA-256加密
sha512Hex:SHA-512加密
md5:MD5加密,返回16位字符串

12 org.apache.commons.collections.CollectionUtils

isEmpty:是否为空
select:根据条件筛选集合元素
transform:根据指定方法处理集合元素,类似List的map()
filter:过滤元素,雷瑟List的filter()
find:基本和select一样
collect:和transform 差不多一样,但是返回新数组
forAllDo:调用每个元素的指定方法
isEqualCollection:判断两个集合是否一致

13 org.apache.commons.lang3.ArrayUtils

contains:是否包含某个字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组

14 org.apache.commons.beanutils.PropertyUtils

getProperty:获取对象属性值
setProperty:设置对象属性值
getPropertyDiscriptor:获取属性描述器
isReadable:检查属性是否可访问
copyProperties:复制属性值,从一个对象到另一个对象
getPropertyDiscriptors:获取所有属性描述器
isWriteable:检查属性是否可写
getPropertyType:获取对象属性类型

15 org.apache.commons.lang3.StringEscapeUtils(废弃)

unescapeHtml4:转义html
escapeHtml4:反转义html
escapeXml:转义xml
unescapeXml:反转义xml
escapeJava:转义unicode编码
escapeEcmaScript:转义EcmaScript字符
unescapeJava:反转义unicode编码
escapeJson:转义json字符
escapeXml10:转义Xml10
这个现在已经废弃了,建议使用commons-text包里面的方法。

16 org.apache.commons.beanutils.BeanUtils

copyPeoperties:复制属性值,从一个对象到另一个对象
getProperty:获取对象属性值
setProperty:设置对象属性值
populate:根据Map给属性复制
copyPeoperty:复制单个值,从一个对象到另一个对象
cloneBean:克隆bean实例

现在你只要了解了以上16种最流行的工具类方法,你就不必要再自己写工具类了,不必重复造轮子。

另外,工具类,根据阿里开发手册,包名如果要使用util不能带s,工具类命名为XxxUtils。

本文部分内容参考:https://www.jianshu.com/p/64519f1b1137

                               https://blog.csdn.net/weixin_41704428/article/details/80342117

                               https://blog.csdn.net/u012060033/article/details/89326485

发布了8 篇原创文章 · 获赞 1 · 访问量 158

猜你喜欢

转载自blog.csdn.net/qq_35599414/article/details/104990986