A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© g207776411 中级黑马   /  2018-4-14 14:28  /  495 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 小石姐姐 于 2018-4-20 09:36 编辑

笔记总结



Day05   常用API,日期的转换,包装类,正则表达式常用API
  • Object类

    • 所有的类一开始没有继承其他的类之前都默认继承Object类
    • 一个类虽然继承了其他的类,但是他的父类总有一个是会继承Object类的,所以类一定会继承Object类



  • String toString():返回该对象的字符串表示        return getClass().getName()+"@"+Integer.toHexString(hashCode());        
  • getClass();返回一个字节码对象
  • getName();返回字节码的名字
  • toHexString方法就是以十六进制(基数16)无符号整数形式返回一个整数参数的字符串表示形式
  • hashCode():返回该对象的哈希码值(内部地址值)


获取字节码文件对象的方式
  • 第一种

    • 用class对象来调用

      • Class 变量名=当前类的对象.getClass()
        Calss c=类.getClass();
        System.out.println(变量名);        



  • 第二种

    • 用类名来直接调用class

      • .class是一种特殊形式,称为字面常量
      • Class 变量名 =当前类名.class();
      • Class c=Student (类名).class()
      • System.out.println(变量名);



  • 第三种

    • 用Class类的静态方法forName()来获取

      • Class 变量名=Class.forName("类的完整的类名")   在哪个包下的哪个类例如 itheima_01.Teacher;
      • Class clazz=Class.forName("com.itheima.student")




注意:同一个类下创建的对象的字节码值是一样的,例如一个类创建两个对象,分别是c1 c2 ,那么 c1.getClass()  =c2.getClass();
学习反射的时候,我们可以获得任意一个类的对象,并且调用它的方法和成员变量
object中的equals
  • 因为Object 中的equals比的是我们new 类的对象的地址值,每个地址值都不相同,所以返回肯定都是false
  • 这里我们就需要重写equals方法
    比较Person p=new Person("liming",18);                Person p2=new Person("liming",18); p和p2是否相等        

    //因为所有的类都继承自Object类,所以 Object b类就是继承Object类的子类
    //传入一个Object类的对象
        public boolean equals(Object b){
    //为了提高效率 当前对象和传递进来的地址值相等的时候,那他们就相等
            if(this==b){
            return true;
        }
    //提高代码的健壮性,就是安全性,看看他们两个类的类型是否相同
        if(this.getClass()!=b.getClass()){
            return false;
        }   

    //将父类强转成子类
        Person per=(Person)b;
        //分别比较类中的成员变量
        if(!this.name.equals(per.name)){
            return false;
        }
        if(this.age!=per.age){
            return false;               
        }
        //两者都能执行下去,那么就返回true
        return true;
    }

System类常用的成员方法
    * 类字段,System.out.println(),out就是类字段,
    * err 错误输入流
    * in  输入流
    * out 输出流               
  • arraycopy 赋值数组


    * 格式 System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
    src表示源数组
    dest表示目标数组
    srcPos表示起始要复制的元素的索引值
    destPos表示从目标文件的哪个索引值开始复制,
    length表示要复制的数组的长度
  • currentTimeMillis():以毫秒值返回当前系统的时间(1970-1-1  0:00:00)

    • 1000毫秒=1秒

      • 相当于1970年-1-1 0:0:0     0

        • 如果系统时间1970-1-1 0:0:1  1000
        • 如果系统时间1970-1-1 0:1:0  1000*60
        • 如果系统时间1970-1-1 1:1:0  10006060+1000*60*终止程序的方法  static void exit(int status) 参数非0表示异常终止




  • Date 方法
  • Date的构造方法

    • Date方法,能够表示特定的瞬间,精确到毫秒,他可以同过方法来设定               自己所表示的时间,可以表示任意的时间

      • 构造方法就是创建对象,
      • 构造方法:
      • Date():创建的是一个表示当前系统时间的Date对象
      • Date(long date):根据"指定时间"创建Date对象





    *   毫秒值转----Date
        *           Date d=new Date(毫秒值);
        *           System.out.println(d);
        *               设置
        *               返回值是void.参数long
        *           构造方法也可以
        *           void setTime(long time);
        *           Date(long date)
        *      
    *           Date---毫秒值
        *               获取
        *               返回long.无参数
        *               long.setTime()  设置时间
        *               long getTime()
                        
## 举例 :
    *当有要求输出当前时间点
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日  HH:mm:ss:SS")
    Date date =new Date();
    String s=sdf.format(date);
    System.out.println(s); //输出2018年04月07日18:37:54:721
    解析:
    Date d=new Day("")
    String s=abf.parse();
  • SimpleDateFormat 用于格式化日期 他的父类是Format
  • 他的子类是simpleDateFormat 格式化:                                 Date---String
    ​        用parse方法来将String类型的日期文本转换为Date日期对象
    ​                        date对象接收= new SimpleDateFormat.parse(String text, ParsePosition pos)
                                     2049-8-26 2049年8月26日                         解析: String ---Date                                 "2049-8-26"                                 Date parse(String source)                                 因为字符串不能用来算数,所以我们就需要调用Date方法来转换成毫秒值来实现
  • 注意:Exception in thread "main" java.text.ParseException: Unparseable date: "2018年04月07- 18:37:54:721"
  • 解析成字符串输出的时候,字符串的模式必须和构建对象的模式一样


速记小技巧 :   00年00月00日 就是4个小姨2个大美眉和2个小弟弟
  • Calendar: 日历,提供一些操作年月日时的方法

    • Calendar c=new Calendar();
    • 修改
    • 添加
    • getInstance() :
    • 使用默认时区和语言环境获得一个日历
    • 修改 : void set(int  field,int value); 把字段修改成之指定字段

      • set方法一定要在你获取这个日历之前修改使用


    • 添加 void add (int field,int value);在指定的字段上加上指定的值

      • c.add(Calendar.它的字段名,-1)


    • 获取,查看  int  接收值 =c.get(int field)int month= c.get(Calendar.MONTH);//获取月,         ....最后用输出字符串连接成时间格式,年 月  日



包装类的概述和基本使用
由于基本数据类型只能做一些简单的操作和运算,所以Java为我们包装了基本数据类型,为每种基本数据类型提供了包装类.
包装类就是封装了基本数据类性的类,为我们提供了更多复杂的方法和一些变量
我们有四类八种基本数据类型他们分别都包装了基本类型
byte        Byte
short       Short
char        Character
int         Integer
long        Long
float       Float
double      Double
boolean     Bollean

Integer
        相互转换
        int a = new Integer("60").intValue();
        String---int
        int---String
Integer的转换方法
        Integer(int  value)
            String s=new Integer().Integer(60);
            
        Integer(String s)
        
        int intValue()
        
        static int parseInt(String s)
        
        static String toString(int i)
        
Integer的构造方法
//Integer(String s)
    Integer i=new Integer("10");
    System.out.println(i);

     将字符串转换为int类型
    Integer i=new Integer("60");
    int a = i.intValue();
    System.out.println(a + 30);
   * 因为我们需要在不创建Integer对象的情况下来转换字符串,所以我们必须选择一个静态方法      
    Integer 相互转换
        //      方式1; int类型接收 =new Integer("字符串").intValue();
        //      方式2;static int parseInt(String s);
        //      String---int
        //      
        //      int---String
        //      方式1:直接加空字符串"" + int
        //      方式2: 用toString方法
        //      方式3: static void toString(int i);
        // Integer的构造方法

        // Integer(Strings)
        // Integer i=new Integer("10");
        // System.out.println(i);

        // 将字符串转换为int类型
        // int a = new Integer("60").intValue();
        // System.out.println(a + 30);
        
        //static int parseInt(String s);包装类自动装箱和拆箱  JDK1.5的特性
自动装箱就是基本数据类型转引用类型
自动拆箱就相当于将引用类型转换为基本数据类型
Interger i=10;
Interger i2=20;
Interger i3=i+i2;
//Integer i3 = new Integer(i.intValue()+i2.intValue());正则表达式验证方法正则表达式验证方法
​        *  Pattern类,在API中查询Pattern类查询正则表达式
  • 正则表达式就是一套通用的规范,用于匹配字符串的是否符合规则


比较格式: boolean matches (String  regex):判断是否符合正则表达式的规范
日期中常用的转换方法
​                1)Date对象转转毫秒值

        Date d=new Date();

        long 毫秒变量接收 =  d.getTime();
​                2)毫秒值转Date对象  setTime没有返回值,所以不需要Date对象接收

            Date d=new Date();

            d.setTime(d.getTime());
​                3)String日期字符串转Date对象  (叫做解析)

调用SimpleDateFormat方法parse(); 返回一个Date对象,

        定义SimpleDateFormat 的对象

        SimpleDateFormat  sdf=new SimpleDateFormat("日期规范");

        Date d=sdf.prase("日期字符串对象或者日期字符串的String常量")
​                4)Date对象转String

        Date d =new Date();

        String  s=adf.format(d);

        System.out.println(s) ;//我们此时输出的就是符合我们定义的规范的日期,输出日期字符串
巧记:毫转时间用set,时间换毫秒用get(并且long接收),        
​                5)Calendar方法  用于获取年  月  日  小时 分钟  秒
​                        注意:  有意Calendar是一个抽象类 ,要想调用Calendar 的对象,我们可以直接调用它的静态方法Calendar cal= Calendar.getInstance();  用Calendar对象来接收
​        注意:
​                Calendar cal= Calendar.getInstance();
​                Date对象转Calendar,这里主要使用来获取改变的Date日期,然后用Calendar来获取并且输出
​                        cal.setTime(Date对象);    例如: cal.setTime(new Date());
​                获取
​                        int year=cal .get(Calendar.YEAR)  ;//实际上就是调用Calendar中的成员变量
​                修改
​                             cal.set(Calendar.YEAR, 要修改成的年份);
​                添加
​                        cal.add(Calendar.MONTH,要修改的月份,如果是负数,那就是日期待退多少);
Day06 List集合,迭代器,泛型,Collection常用功能ArryList 集合的体系结构
​                体系结构:                1)因为不同功能的数据结构(数据的组织,存储方式),所以Java 为我们提供了不同的集合
​                  2)但是不同的集合它们的功能都是相似的,我们可以不断的向上抽取,提取共性
Collenction常用功能
  • Collection类
    ​        Collection c=new ArrayList();
    add 添加
    clear 清除 清空
    boolean contains (Object o);判断集合中是否包含指定元素
    bollean remove(); 如果删除成功,则返回true
    bollean isEmpty();  是否为空  如果有元素,则返回false
    Object[]  toArray():将集合转换成一个Object类型的数组        

            for(int =0 ; i<objs.lenth;i++){
                    System.out.println(objs);
                }迭代器
    ​                迭代器中的方法
    ​                首先迭代器   Iterator it=集合对象. iterator();
    ​                        for(it.hasNext())}{
    ​                                System.out.println(集合对象.next());
    ​                        }
    实际上就是遍历集合
    ​                构造方法
    ​                boolean hasNext(); 是否存在下一个元素
    ​                E next(); 返回迭代的下一个元素
    ​                void remove(); 从迭代器指向的collection中移除迭代器返回的最后一个元素
    迭代的意思: 就是重复执行某一操作,类似于循环
    ​                //迭代遍历集合
    ​                Iterator iterator=new Iterator();
    ​                for(iterator.hasNext())
    ​                {
    ​                        System.out.println(list.next());        
    ​                }
    ​        *  用迭代来判断集合中的元素,并且用集合 来操作添加元素,会报错



      *  报错的原因是,迭代实际上是集合的副本,集合中没有的副本,我们用迭代就执行不了,迭代器依赖于集合
         *  报错提示   **ConcurrentModificationException**
​        
   重点注意:
           迭代器依赖于集合,相当于集合的副本        (我们通过迭代器修改集合中的元素,因为迭代器和集合是同步的)
并发修改异常
迭代器的添加方法:
                   我们可以调用Iterator的儿子的方法来实现添加元素 List子类           

   
List l = new ArrayList();           //创建集合对象
ListIterator li=l.ListIterator();  //迭代
while(li.hasNext()){
    li.add("C++");  //用迭代器添加,因为迭代器是和集合是同步的
    System.out.println(l);
}泛型
泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,就是在还没执行程序之前就会提醒你,捷键了数组的特点(类型不同,不允许存储)
​                *  泛类就是和集合格式一样                *  ArrayList<泛类,就是要存储的数据类型> arr=new ArrayList<String>();                *  类的格式为         类名<E>类型的类,都可以指定泛类        
​                泛型只存在于编译之前,编译以后,系统功能会擦出泛型
  • 好处:
  • 避免了类型转换的问题
  • 可以减少黄色警告线
  • 可以简化我们代码的书写



    // 创建集合对象
    Collection<Student> c = new ArrayList<Student>();
    // 创建元素对象
    Student s1 = new Student("张三",19);
    Student s2 = new Student("李四",18);
    // 添加元素对象
    c.add(s1);
    c.add(s2);
   // 遍历集合对象
   //用迭代器遍历数组
   Iterator<Student> it=c.iterator();
   while(it.hasNext()){
    Student stu=it.next();
    System.out.println(stu);
   }foreachforeach
​        这是一个增强for循环        
  • foreach:增强for循环.一般用于遍历集合或者数组
  • 格式:
  • 先创建集合对象
    ArrayList arr=new ArrayList();                 for(集合元素的类型    变量:集合或者数组对象){                         可以直接使用变量;                         }
  • public interface Iterable<T>
  • 实现这个接口的对象才能使用"foreach"语句


常见的数据结构
  • 数组:

    • 一旦定义就不能改变,

      • 查找快,增删慢.链表:由链子链接起来的一堆结点        结点: 地址值,值,下一个结点的地址值1,2,3,4,5                 例如:





  | 0x0011 |  1 | 0x0022 |
  | 0x0022 |  2 | 0x0033 |
  | 0x0033 |  3 | 0x0044 |
  | 0x0044 |  4 | 0x0055 |
  | 0x0055 |  5 |        |
如何获取结点3?如何获取结点3?        只能遍历链表,然后一个个查看,        要在结点2后面添加一个新的结点8?                把结点2的下一个结点地址值修改为结点8的地址值,把新节点8的下一个地址值改为3结点的地址值        缺点:查询慢增删快        
栈和队列的特点
栈是先进后出,
队列是先进先出列表List
List 的元素排列顺序是依次排列和Array List一样        常用方法:                先创建对象                                List list=new ArrayList();                        添加:  void add (int index,E element)                                                list.add();                        修改: E remove (int index):将指定索引位置的元素替换,并且返回原来的元素                                list.set(0,"android");                        获取:E get (int index)根据索引返回元素                                list.get();                                注意: 在获取的时候也不能发生越界,即获取它不存在的索引的元素                                
  • List的子类的特点,和ArrayList的特点

    • Array List的底层是数组                                特点,查询快,增删慢                LinkeList的底层是链表                                特点,查询慢,增删快                如果不清楚使用什么来对数组进行操作,那么我们一般选择ArrayList                LinkeList的元素排列顺序是,来得越早,你越靠后**                LinkeList的特有功能                        void  addFirtst(E e)                        void  addLast(E e)                        E getFirst();                        E getLast();                        E removeFirst();                        E removeLast();


      ​
    Day 07 Set接口 Map键值对Set接口的特点
    使用HashSet字符串并遍历
    set的特点:     * 无序(存储时的顺序有可能和输出的顺序不同)     * set存储时不允许重复(要求元素唯一)     * 因为它存储时时无序的,所以它没有索引值


                    set方法不存在索引添加元素的特征
                    HashSet的父类是Collection(存储\收集的意思)HashSet

        在同一类当中,创建的所有对象的hash码值都不相同
            所以当判断这两个对象是否相同的时候,先判断他们的Hash码值,
    • 当两个对象的hash码值都不相同但是他们的初始化值相同的情况下,我们需要重写hash码值(统一返回一样的hash码值),这样我们才能用equals方法比较他们的成员变量是否相同

      • 使用HashSet存储字符串并遍历
      • 当添加的元素为类的不同的对象的时候,即这两个对象的hash值不相同


    • 通过查看源码发现 :

      • HashSet的add()方法,首先会使用当前集合中的每一个元素比较和新添加的元素进行hash值比较如果hash值不一样,则直接直接添加新的元素                         如果hash值相同,比较地址值或者继续用equals来进行比较                         比较结果如果不相同,则认为重复不添加                         如果所有的比较结果都不一样,则添加(所有的意思指的是当前集合中的所有元素)



    • 我们发现,当hashCode方法永远返回整数1时,所有对象的hash都是一样的
    • 有一些对象他的成员变量完全不同,但是他们还是要进行hash和equals方法的比较
    • 如果我们可以让成员变量不同的对象,他们的hash值也不同,着样就不用在进行多余的比较了
    • 从而可以提高我们程序的效率
    • 我们可以尝试让hashCode方法的返回值和对象成员变量有关,我们需要返回成员变量之和基本数据类型直接相加(这里我们需要重写hashCode方法),
    • 然后用引用数据类型获取hashCode方法返回值后再相加(boolean类型不可以参与运算)


    ha'shCode方法优化

        如果让hashCode()方法返回一个固定值,那么每个新添加的元素都要调用equals(Object obj)方法比较,那么效率较低
       只需要让不同属性的值的元素产生不同的哈希值,那么就可以不再调用equals方法比较提高效率
    ​        
    重写equals方法

    重写equals时,如果我们传入的参数是一个没有泛型的类型,
    那么我们向下转型成当前类的对象有可能会报错,所以我们这里需要判断当前类对象和传入的类的对象,
    //重写equals方法
    public boolean equals(Object obj) {
        System.out.println("-----");
        //如果泛型不同,我们需要提高效率
        if(this==obj){
            return true;
        }
        //比较传入的对象的字节码值,如果相同,则代表他们时同一个类中的变量.则不需要在比较.直接
        if(this.getClass()!=obj.getClass()){
            return false;
        }
        //我们需要先向下转型成当前类的对象
        Person p =(Person)obj;
        //接下来我们比较他们的年龄,如果当前的成员变量与初始化的成员变量值相同
        if(this.age!=p.age){
            return false;
        }
        //接下来判断行姓名
        if (this.name!=p.name) {
            return false;
        }
        //如果以上条件都不执行,则默认他们相同
        return true;
    }Collections工具类的方法
    • static int binarySearch(List list,Object key);
      二分法(参数中只能是List集合,因为Set等集合,他们是无序的)不断的取中间值,如果中间值小于给出的数,那么就只比较中间值以后的,如果中间值大于给出的数,那么就判断这个
    • static  void fill (List list,Object obj);使用指定元素替换指定列表中的所有元素
    • static void copy(List dest ,List src):把源列表中的数组覆盖到指定目标列表(注意:目标列表长度至少等于元列表的长度)
    • static void reverse(List list): 反转,
      .3.1        案例代码四:package com.itheima_03;


    import java.util.ArrayList;import java.util.Collections;import java.util.List;
    /*
    • Collections:
    • 面试题:Collection和Collections有什么区别?

      • Collection是集合体系的最顶层,包含了集合体系的共性Collections是一个工具类,方法都是用于操作Collection


    • */




    public class CollectionsDemo {
    public static void main(String[] args) {
        //static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(4);
        Collections.swap(list, 0, 1);
       
        System.out.println(list);

    }

    private static void method6() {
        //static void  sort(List<T> list) :按照列表中元素的自然顺序进行排序
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(4);
        list.add(3);
        list.add(2);
       
        Collections.sort(list);
        System.out.println(list);
    }

    private static void method5() {
        //static void shuffle(List list):傻否,随机置换  
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Collections.shuffle(list);
        System.out.println(list);
    }

    private static void method4() {
        //static void reverse(List list)  :反转
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        Collections.reverse(list);
        System.out.println(list);
    }

    private static void method3() {
        //static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
        List<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("java");
        System.out.println(list);
       
        Collections.fill(list, "android");
       
        System.out.println(list);
    }

    private static void method2() {
        //static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
        //注意:目标列表的长度至少等于源列表的长度
        //创建源列表
        List<String> src = new ArrayList<String>();
        src.add("hello");
        src.add("world");
        src.add("java");
       
        //创建目标列表
        List<String> dest = new ArrayList<String>();
        dest.add("java");
        dest.add("java");
        dest.add("java");
        dest.add("java");
        Collections.copy(dest, src);
        System.out.println(dest);
    }

    private static void method() {
        //static int  binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        int index = Collections.binarySearch(list, 4);
        System.out.println(index);
    }
    }
    Map方法
    构造方法
    public interface Map<K,V>
    ​                将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
    特点:        键是唯一的        键不能重复,值可以        键是无序的
    • Collection 和Map的区别?

      • Map是一个双列集合,常用语处理有对应关系的数据,key时不可以重复的,我们也称之为夫妻对集合Collection:是单列集合,Collection有不同的自体系,有的允许重复有索引有序,有的不允许重复而且无序,那么我们也称之为单身汉集合



    Map的常用功能


    添加
        // V put(K key, V value)  添加元素方法
        System.out.println(map.put("it001", "张五"));
        System.out.println(map.put("it002", "李明"));
        System.out.println(map.put("it003", "小明"));
    判断
        boolean containsKey(Object key)
          如果此映射包含指定键的映射关系,则返回 true。
        containsValue(Object value)
          如果此映射将一个或多个键映射到指定值,则返回 true。
    删除
        void remove("it002"); 清除指定的键 的键值
        void clear()   清除所有的键值对
    遍历
        Set<Map.Entry<K,V>> entrySet()
          返回此映射中包含的映射关系的 Set 视图。
    Map的第一种遍历方式:        keySet();先获取所有的键,然后根据键来找值


    Set<E> st=map.keySet();
        Set<Student> key1 = map.keySet();
            for (Student student : key1) {
                System.out.println(student.toString());
            }
       
    Map的第二种遍历方式:        entrySet();(相当于结婚证)


    //定义一个Map
        Map<String,Integer> map=new HashMap<String,Integer>();
        map.add("小明",18);
        map.add("小张",19);
        map.add("小米",20);
        //创建set集合获取结婚证
        HashSet<Entry<Student, String>> entrySet = map.entrySet();
             for (Entry<Student, String> entry : entrySet) {
                System.out.println("同学姓名"+entry.getKey());
                System.out.println("同学年龄"+entry.getValue());
        可变参数

    在类型明确,参数数量不确定的时候. java可以把多个参数直接转换成数组
    • 注意在添加了可变参数的时候,不允许在行在的可变参数后面追加参数;例如不能这样写(int...arr,int a),


       但是可以在可变参数的前面添加
    ​    可变参数可以给多个,或者一个也不给也不会报错


    例如:
        sum(1,2,3,4,5,6);
        public static int sum(int...arr){
            for(int i=0; i<arr.length; i++){
                    sum+=i;            
            }
            return sum;
    ​        
    Day08 异常,递归异常处理
    • 它发生在编译和运行的时候,
    • 注意:_Error(不应该试图捕获的严重问题,不能处理的异常)


    异常的体系结构        


    Java.lang.Throwable(最顶层)
                    |_Error(不应该试图捕获的严重问题,不能处理的异常)
                    |Exception(可以处理的异常)  #编译时异常:编译时期就会发生的异常
                        |RuntimeException   #运行时异常:编译时正常,运行时才会发生的异常异常的处理方式:

    JVM处理异常的方式:
        如果异常没有处理,jvm会帮我们进行处理,他会把异常的类型,原因还有位置显示在命令行,并且还终止了程序,异常后面的代码将不再执行


    try...catch语句
    我们自己进行异常处理的方式:


    try{
       有可能会出现问题的代码;
    }catch(ArithmeticException ae(填写异常)){
        处理异常;
    }
    try...catch的执行顺序
    • 首先执行try语句
      ​                如果发现异常,异常下面的代码不再执行,直接跳入catch语句中,catch语句结束后,整个try...catch语句结束                如果没有发现异常,那么catch语句中的代码不会执行                在try..catch语句中,发生的异常,他们存在子父类关系,那么子类异常在上,父类异常在下
    • 抛出编译时异常:throws
    • 主动抛出异常:throw


    异常分类

    两大类
         |运行时期异常:RuntimeException的子类就是运行时期异常,在编译时期可以自由选择处理或不处理
         |编译时期异常:是Exception的子类,非RuntimeException的子类自定义异常应用场景
    ​                        当我们在捕获异常时,系统所给的异常提示满足不了我们的需求,这时候我么你需要自己定义自定义异常;  
    自定义异常:
    • 实际上就是我们自定义运行时期异常类和编译时期异常类,并分别实现他们对应的父类的有参和无参构造;
    • 创建运行时期异常的子类
      ​        // 子定义运行时期子类,并且实现父类有参和无参方法        class MyRunException extends RuntimeException {

      public MyRunException() {
          super();
          // TODO Auto-generated constructor stub
      }

      public MyRunException(String message) {
          super(message);
          // TODO Auto-generated constructor stub
      }
    • 创建编译时期异常类
      // 子定义编译时期子类,并且实现父类有参和无参方法class MyException extends Exception {

      public MyException() {
          super();

      }

      public MyException(String message) {
          super(message);

      }
      }


    多异常处理
    • 多异常的捕获:

      • 可以写多个catch代码块来分别处理同一个try代码块中的多个异常


    • 多异常捕获中catch的顺序

      • 如果被捕获的异常类没有继承关系, 则catch的顺序可以随意定义
      • 如果异常是继承关系的类, 必须子类异常在上, 父类异常在下

        • 原因: 因为父类包含子类的异常, 如果上方被父类异常的catch捕获了, 那么捕获子类异常的catch永远也不会用到



    • 多个catch代码块的执行逻辑

      • try代码块中抛出的异常, 如果catch中有对应的具体异常, 则执行对应的catch代码块. 其他catch代码块不会执行(类似于if...else if, switch...case)
      • try代码块中抛出的异常, 如果catch中没有对应的具体异常, 则所有catch代码块都不会执行. 相当于异常没有捕获, 仍然会导致程序终止





    try {
        // 可能发生异常的代码
    } catch (异常类型1 异常对象名1) {
        // 处理异常1的代码
    } catch (异常类型2 异常对象名2) {
        // 处理异常2的代码
    }
    • 补充: JDK1.7新特性: 在一个catch中捕获多个异常类型

      • 在一个catch的参数中填写多个异常类型, 格式: catch (异常类型1 | 异常类型2 异常变量名) {}
      • 注意

        • 不同异常类型之间用|分隔, 变量名只有一个
        • catch代码块中, 由于不同异常类型都只对应同一个变量名, 所以在需要判断是哪种异常时, 可以使用变量名 instanceof 异常类型来判断具体是何种类型; 如果不需要针对具体异常类型分别处理, 可以不判断异常类型, 统一通过异常变量名来做统一的处理, 示例如下:






    // 格式
    try {
        // 可能抛出异常的代码
    } catch (异常类型1 | 异常类型2 异常变量名) {
        // 异常处理代码
        if (异常变量名 instanceof 异常类型1) {
            // 处理异常类型1
        } else if (异常变量名 instanceof 异常类型2) {
            // 处理异常类型2
        }
    }

    // 一般这样处理是因为2种异常的处理方式相同, 才合并写; 否则可以使用catch语句方式分别处理Throwable的常用方法
    • Throwable类

      • 常用成员方法

        • String getMessage(): 异常的信息. 没有原因返回null
        • String toString(): 异常的类型和原因
        • void printStackTrace(): 使用标准错误输出流打印异常信息




    finally概述和引用场景

      - finally关键字
        - 作用:
          - 与try...catch配合, 无论异常是否被捕获, 最终都会执行finally代码块中的代码
        - 应用场景:
          - 如IO流的关流操作, 无论IO操作过程中是否出现异常, 最终都要关流, 避免程序占用资源. 所以一般都在finally代码块中进行关流操作
        - 格式:

      ```java
      try {
        // 可能发生异常的代码
      } catch (异常类型 异常变量名) {
        // 对捕获异常的处理
      } finally {
        // 无论是否捕获异常, 都需要执行的操作
      }
      ```

      - 提前认识一下IO流操作的标准写法:

      ```java
      FileWriter fw = null;              // 在try代码块外初始化, 这样finally中才能访问到
      try {
        fw = new FileWriter("a.txt");  // 创建输出流对象, 会抛出FileNotFoundException异常
        fw.write("hello");             // 会抛出IOException
      } catch (IOException e) {          // IOException是FileNotFoundException的父类, 可以多态形式捕获
        // 处理异常
      } finally {
        // 关闭流
        if (fw != null) {              // 判断fw是否为null, 避免空指针异常
            try {
                fw.close();            // 关闭流, 会抛出IOException
            } catch (IOException e) {
                e.printStackTrace();   // 打印异常. 开发中一般不会打印出来, 而是存入日志
            }
        }
      }
      ```

      •递归的注意事项:
    ​        递归一定要有出口,内存溢出        递归次数不宜过多,内存溢出


        斐波那契列数;
        public class Test2 {
            public static void main(String[] args) {
                int number1=method(10);
                int number2=method(9);
                //求斐波那契列数
                double d=number2*1.0/number1;
                //输出值
                System.out.println(d);
        }
            public static int method(int n) {
                if(n==1){
                    return 1;
                }else if(n==2){
                    return 1;
                }else {
                    //假如传入的数据每次都不符合if和else if的条件,
                    //那他就一直调用自身方法相加
                    return  method(n-1)+method(n-2);
                }
            }
    }
    递归优点
    ​                减少代码的书写
    递归的缺陷:
    ​                代码识辨识性差,一般情况下使用for循环

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马