day15-try-catch_finally + 集合迭代器的使用(使用迭代器增删改查)

1.try-catch-finally:异常捕获机制

(1)常见的用法就是来捕获异常,将可能出现异常的代码放入try{}代码块中,随即对应的catch{}中写异常的处理方式(可以throw抛出)。

(2)如果有多条代码都可能出现异常,而且都要捕获他们然后写对应的处理方式,保证程序能够正常执行下去时候,这个时候我们不能将所有可能出现异常的代码放在一个try中,因为当try中的一条语句出现异常时候,这时候就进入了对应的catch中了,那在try中之后的代码也就不会执行了,那异常自然不可能捕获到,更别说处理了。此时我们需要将每一句可能出现的异常的代码单独放入一个try中,并且有一个与之对应的catch处理。(注意有很多catch捕获异常时候,要注意先子类后父类的顺序,因为如果在开始就被父类全部捕获到了,后面的也就捕获不到异常了,既各个具体的XXXException放在前面,后面放一些其他的异常都用Exception).

public static void main(String[] args) {
        // TODO
        int[] a = new int[3];
        String s = "abc";
        Student student = null;
        int num;
        Score score = null;
        
            try {
                num = Integer.parseInt(s);
            } catch (NumberFormatException e) {  //捕获数字转换异常
                e.printStackTrace();
                num=0;
            }
            try {
                System.out.println(student.getName());
            } catch(NullPointerException e) {   //捕获空指针异常
                e.printStackTrace();
                student = new Student();
                student.setName("张三");
            }
            try {
                score = Score.valueOf(Score.class, "S");
            } catch (IllegalArgumentException e) {  //捕获非法参数异常
                e.printStackTrace();
                score = Score.valueOf(Score.class, "E");
            }        
            try {
                 System.out.println(3 / 0);    
            } catch (Exception e) {     //其他异常不分了  都进来
                e.printStackTrace();
            }    
            finally {
                System.out.println(student.getName());
                System.out.println(num);
                System.out.println(score);
            }

        }
    }

(3)还可以看到我在上面的代码中,在每个catch中都对可能出现异常后的情况进行了修复,这就可以保证我的程序在正常运行的时候,可能由于一些小的问题出现了异常,但是经过处理后,程序还能正常的执行下去,不会导致程序直接死掉。

运行结果:

//这是捕获到的各种异常信息,都打印出来了
java.lang.NumberFormatException: For input string: "abc" at java.lang.NumberFormatException.forInputString(Unknown Source) at java.lang.Integer.parseInt(Unknown Source) at java.lang.Integer.parseInt(Unknown Source) at com.qfedu.exception.Test1.main(Test1.java:16) java.lang.NullPointerException at com.qfedu.exception.Test1.main(Test1.java:22) java.lang.IllegalArgumentException: No enum constant com.qfedu.enumdemo.Score.S at java.lang.Enum.valueOf(Unknown Source) at com.qfedu.exception.Test1.main(Test1.java:29) java.lang.ArithmeticException: / by zero at com.qfedu.exception.Test1.main(Test1.java:36) //这是处理后,正确的要输出的结果 张三 0 E

 

2.try-catch-finally中都含有return语句时候的执行顺序跟结果

(1)看下面代码(基本数据类型或者String类型时候)

public static int test() {
        try {
            return 1;
        } catch (Exception e) {
            return 2;
        }finally {
            return 3;
        }
    }

执行结果为3;

public static int test() {
        int i = 5;
        try {
            return i+1;
        } catch (Exception e) {
            return i+2;
        }finally {
            i=9;
        }
    }

执行结果为6。

我们都知道finally中的代码是一定会执行的。

所以从上面两个可以看出来,当finally中有return时候,都以finally中的为准;

当finally中没有return时,在finally中修改变量值的时候,是没有效果的,此时以try-catch为准(没有异常就try,有异常就catch)。

(2)引用数据类型(自定义类型)

public static Student test() {
        Student student = new Student();
        try {
            student.setName("123");
            return student;
        } catch (Exception e) {
            student.setName("456");
            return student;
        }finally {
            student.setName("789");
//            return student;   //都有return时候 毫无疑问以finally中为准
        }
    }

此时返回的student中的getName()为  789

当是一个引用类型的时候,此时在finally中修改就可以起作用了,就要以finally中修改后的为准。

原因:返回的是基本的数据类型或者字符串的时候,当执行到try中的return时候会先将此时的返回值复制一份暂存到一个局部变量区中,此时去执行finally代码,修改变量的值(修改的是的临时的),当finally执行完毕后,又将局部变量区中刚暂存的取出来返回,所以你finally中怎么修改都跟我这个没有关系,我最后取到的还是我最初存进去的一样。

但是如果返回的是引用数据类型那就不一样,我们都知道引用类型在栈中存的都是一个引用的地址,然后指向具体的堆空间。虽然执行过程跟基本的数据类型是类似,当try中return时候,也会复制一个临时的变量引用,当在finally中修改引用类型的基本属性值时候,此时临时引用和原来引用指向的都是同一个区域,那么由临时引用引起的改变,也必将导致原引用指向也会改变,因为是地址的指向,操作的都是同一片区域,所以此时原来的内容也就会发生改变。(跟值传递和引用地址传递是类似的)

 

3.集合迭代器的使用(增删改查)

public static void main(String[] args) {
        /**
         * 1.向集合中添加三个学生对象,使用基本的迭代器输出每个学生的基本信息 
         * 2.使用迭代器删除集合中的第二个元素 
         * 3.使用迭代器向集合的首位插入一个学生对象
         * 4.实例化一个新的学生对象,使用迭代器替换掉集合末尾的元素
         */

//1. List
<Student> list = new ArrayList<>(); list.add(new Student("张三", "133")); list.add(new Student("李四", "110")); list.add(new Student("王五", "122")); // 普通的迭代器 Iterator<Student> iterator = list.iterator(); while (iterator.hasNext()) { Student student = iterator.next(); System.out.println(student.getName() + "\t" + student.getPhoneNum()); // 下面写法错误,因为调用一次next()方法后,就会往后移动一个位置,所以就不能匹配,而且最后还会出界 // System.out.println(iterator.next().getName()+"\t"+iterator.next().getPhoneNum()); } // 2. // 第一种删除 // 迭代器使用一次后再次使用 需要初始化一次,因为上一次的index已经发生改变了 // iterator = list.iterator(); // int index = 1; // while (iterator.hasNext()) { // // 每次向后手动移动一位 // iterator.next(); // if (index++ == 2) { // iterator.remove(); // } // } // 第二种删除 利用listIterator() ListIterator<Student> listIterator = list.listIterator(); while (listIterator.hasNext()) { // 也需要手动移动位置 listIterator.next(); if (listIterator.nextIndex() == 2) { listIterator.remove(); // 删除完成这个后,就跳出,否则会一直删除后面的 break; } } for (Student student : list) { System.out.println(student); } System.out.println(); // 3.首位直接插入 重新初始化后 指向的是开始的位置 listIterator = list.listIterator(); listIterator.add(new Student("sss", "5555")); for (Student student : list) { System.out.println(student); } System.out.println(); // 4.替换末尾的元素 listIterator = list.listIterator(); while (listIterator.hasNext()) { listIterator.next(); // 判断末尾元素 如果当前元素的下一个index等于了集合的长度(角标从0开始),那么当前元素就是末尾的元素 if (listIterator.nextIndex() == list.size()) { listIterator.set(new Student("aaa", "6666")); } } for (Student student : list) { System.out.println(student); } }

使用的注意事项:

(1)如果多次连续操作,那么在一次迭代器使用完毕后,必须重新进行初始化,因为使用完后,此时迭代器的游标就发生变化了,不再是指向最初开始的位置。

(2)如果没有循环输出每一个元素时候(即没有必须使用next()方法),此时若要对集合中指定元素的操作,要自己手动移动游标(即自己调用next()方法,并控制次数),然后移动到自己指定的位置,再开始操作,否则操作的肯定不是你指定的元素。

 

posted on 2018-08-01 21:07  志爱007  阅读(167)  评论(0编辑  收藏  举报