Java知识梳理之异常处理、抽象类与接口(三)

102 阅读2分钟

         部分源码的Github网址为:github.com/hzka/JavaBo… 

(一)异常处理的基础概念
1.异常处理:试想整数除以0会产生一个运行时错误(浮点数除以0不会产生异常),可以使用if判断第二个数字是否为0绕过,但更好地方法是使用try...catch块来处理异常。创建、抛出、捕获以及处理异常。try块包含的是正常情况下执行的代码,catch包含的是异常时执行的代码,throw语句的执行是为抛出一个异常,异常就是一个从异常类创建的对象。异常被catch捕获。直接执行catch后的语句。在这种情况下,异常类是ArithmeticException。一个try...catch...参考P349项目,模板如下:

                                                                            
2.异常处理的优势:能够使方法抛出一个异常给它的调用者,最大的优势是将检测错误(由调用的方法完成)从处理错误(由调用方法完成)中分离出来。以InputMisMatchExecption为例:

public class Main {
    public static void main(String[] args) {
        Scanner input_scanner = new Scanner(System.in);
        int number1 = input_scanner.nextInt();
        int number2 = input_scanner.nextInt();
        try {
            int result = quotion(number1, number2);
            System.out.println(number1 + "/" + number2 + "is" + result);
        } catch (ArithmeticException ex) {
            System.out.println("Exception:an integer cannot be divided by zero");
        }
        System.out.println("Exception continues ..");
        boolean continueInput = true;
        do {
            try {
                System.out.print("Enter an integer:");
                int number = input_scanner.nextInt();
                System.out.println("You created number is:"+number);
                continueInput = false;
            }catch (InputMismatchException ex){
                System.out.println("Try again,inpur is not right");
                input_scanner.nextLine();//discard input
            }
        } while (continueInput);
    }
    public static int quotion(int number1, int number2) {
        if (number2 == 0)
            throw new ArithmeticException("Divisor cannot be zero");
        return number1 / number2;
    }
}

           3.异常类型:

          

      4.异常处理的更多知识:

                                                        
(1)声明异常:使用public static int quotion () throws ArithmeticException声明异常,方法头使用关键字,可以抛出多个异常,使用逗号分隔符隔开。
(2)抛出异常: throw new ArithmeticException("Divisor cannot be zero");注意:声明异常用throws关键字,抛出异常用throw关键字。
(3)捕获异常:try....catch捕获并处理异常。异常有一个反向的方法调用链找到最终的处理器。父类catch块必须出现在子类的catch块之后。譬如:

                                                       
(4)从异常中获取信息:printStackTrace来控制输出栈跟踪信息,getStackTrace提供解决方案。

                                             

public class Main {
    public static void main(String[] args) {
        // write your code here
        try {
            System.out.println(sum(new int[]{1, 2, 3, 4, 5}));
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("\n" + ex.getMessage());
            System.out.println("\n" + ex.toString());
            System.out.println("栈信息");
            StackTraceElement[] traceElements = ex.getStackTrace();
            for(int i=0;i<traceElements.length;i++){
                System.out.println(traceElements[i].getMethodName());
                System.out.println(traceElements[i].getClassName());
                System.out.println(traceElements[i].getLineNumber());

            }
        }
    }
    private static int sum(int[] lists) {
        int result = 0;
        for (int i = 0; i <= lists.length; i++) {
            result += lists[i];
        }
        return result;
    }
}

       5.finally子句:不论异常是否被捕获,都会执行finally子句。其语法和情况如下:


6.何时使用异常:try正常代码,catch异常执行代码,异常处理将错误处理从正常程序设计中分离出来,使得程序易读易更改。当处理不可预料的错误状况时应该使用它,不要用它来处理简单的、可预料的情况。譬如:    

                                                                         
7.链式异常:异常包装、反向、链式。

public class Main {
    public static void main(String[] args) {
        try {
            method1();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.out.println("Hello World!");
    }
    private static void method1() throws Exception {
        try {
            method2();
        }catch (Exception ex){
            throw new Exception("New info from method1",ex);
        }
    }
    private static void method2() throws Exception{
        throw new Exception("New info from method2");
    }
}

(二)示例:
(1)例一:声明、抛出和捕获异常:判断圆半径是否大于零。


(2)例二:创建自定义异常类。没啥技术含量,就是继承自Exception类,重写该类的一些方法,在调用时声明异常、抛出异常。随后写相应的捕获器。
异常类:                                                                      异常声明和抛出:



异常调用:

(三)本章小结

**(四)抽象类和接口
** 1.抽象类:父类设计的很通用,不明确。一个父类设计的很抽象,以至于没有具体的实例,这样的类称之为抽象类。譬如:使用GeometricObject类模拟几何对象共同特征。Circle类和Rectangle继承自这个类。在将GeometricObject设为抽象类之后。最好的方法是将计算面积和周长的方法定义在GeometricObject类中,而实现取决于集合具体类型,不在GeometricObject中实现。与常规类操作的不同:不能使用new操作符创建实例,抽象方法只有定义没有实现,实现由子类提供,有抽象方法的类必须声明为抽象类。参照P371项目。
2.使用抽象类的好处:便于JVM在动态运行时根据对象的类型动态的决定调用哪一个方法。当调用displayGeometricobject(object_01);时,使用Circle类中的getArea方法,当调用displayGeometricobject(object_02);时,使用Rectangle的getArea方法。
3.抽象类的几个关注点:

                       

        4.接口:与类结构相似,在许多方面与抽象类相似,目的是指明多个对象的共同行为,使用正确接口,可以指明这些对象是可比较的、可克隆的。P376项目。需要注意的是:接口中所有数据域都是public final static作为修饰符的,所有方法都是public abstract,所以Jaca允许忽略这些修饰符。
5.抽象类和接口:Java允许为类做单一继承,但是允许对接口做多重继承。接口比类更灵活,参考P376项目。

                                        

       6.将基本数据类型值作为对象处理:因为当作对象处理需要额外系统开销,但许多Java方法需要将对象作为参数。因此可以将int包装成Integer类、将double包装成Double类,此为类包装。每一个包装类都覆盖了Object类的toString和equals方法以及Comparable接口中的ComapreTo方法。所有包装类实例不可变。Integer.pareseInt将数值字符串转为int值,Double.pareseDouble将数值字符串转变为double类型。Integer.parseInt("11",2)结果为3。

                                  

       7.基本类型和包装类型之间的自动转换:

      8.BigInteger和BigDecimal类:可表示任意大小的整数或者实数,加减乘除分别为:add、subtract、multiple和divide。任意整数阶乘的代码如下所示。

public class Main {
    public static void main(String[] args) {
        System.out.println("50!" + factorial(50));
    }
    private static BigInteger factorial(long n) {
        BigInteger result = BigInteger.ONE;
        for (int i = 1; i <= n; i++) {
            result = result.multiply(new BigInteger(i + ""));
        }
        return result;
    }
}

(五)实例:
1.Comparable接口:实现两个相同类型对象中较大者的通用方法,譬如:两个学生,两个圆等等,对象可比较,因此对象有共 同接口为comparable。譬如String、Data等都有相应的Comparable的实现。

                        
2.ActionListener接口:一个对象要成为源对象上动作事件的监听器,需满足两个条件:

                         

                                                

      参考P380项目。
3.Clonable接口:对象拷贝。一个带空体的接口称为标记接口。用来表示类拥有某些特定的属性。实现Cloanale接口的类标记为可克隆的,他的对象可以使用Object类中定义的clone方法克隆。譬如Data、Calen和ArrayList类。我们在这里自定义类实现Clonable接口,并覆盖Object类的clone方法。参考P382项目。
4.对一个数组对象进行排序:这些对象都是Comparable接口的实例,可以使用compareTo方法进行比较,对int、double、char和字符串数组进行了比较,参考P388项目。

public class Main {
    public static void main(String[] args) {
        Integer[] intArray = {new Integer(2), new Integer(4), new Integer(3)};
        Double[] doubleArray = {new Double(3.4), new Double(1.4), new Double(-22.1)};
        Character[] charArray = {new Character('a'), new Character('J'), new Character('r')};
        String[] stringArray = {"Tom", "John", "Fred"};
        sort(intArray);
        sort(doubleArray);
        sort(charArray);
        sort(stringArray);
        printList(intArray);
        printList(doubleArray);
        printList(charArray);
        printList(stringArray);
    }
    private static void printList(Object[] intArray) {
        for(int i = 0;i<intArray.length;i++){
            System.out.println(intArray[i]+" ");
        }
        System.out.println();
    }
    private static void sort(Comparable[] lists) {
        Comparable currentrMin;
        int currentMinIdex;
        for (int i = 0; i < lists.length - 1; i++) {
            //找该list当中的最大值。
            currentrMin = lists[i];
            currentMinIdex = i;
            for (int j = i + 1; j < lists.length; j++) {
                if (currentrMin.compareTo(lists[j]) > 0) {
                    currentrMin = lists[j];
                    currentMinIdex = j;
                }
            }
            if (currentMinIdex != i) {
                lists[currentMinIdex] = lists[i];
                lists[i] = currentrMin;
            }
        }
    }
}

       首先对所有进行数据int、double等封装成Integer、Double、Character以及String,这些类都实现了Comparable接口,可以使用compareTo进行比较。另外,在Array类中,Java提供了任意对象类型的数组进行排序的静态方法sort。Arrays.sort(intArray)。
(六)总结: