Java从零开始 第10讲 包装类和异常处理,变参方法和递归

包装类

通常我们定义参数的时候,我们直接使用数据类型定义,但是为了方便操作,Java为其中的八种基本数据类型都添加了包装类

基本数据类型包装类
intInteger
charCharacter
floatFloat
doubleDouble
booleanBoolean
byteByte
shortShort
longLong

其中的数字类包装类,Integer,Short,Long,Double,Float,Byte都是Number的子类
而Character,Boolean则是Object的直接子类

通过包装类,我们能更新定义参数的方法:
int a = 10;
Integer a = new Integer(10);

其中将10包装为Integer的操作被称为装箱操作,而将Integer转为int类型则是拆箱操作
但是当我们使用下面的代码时,会出现这样的情况
在这里插入图片描述
这就是意味着,这个方法已经过时了,推荐你不要使用,目前Java已经提供了自动装箱和自动拆箱的操作:
Float f1 = 12.34f;// 自动装箱
float f2 = f1; // 自动拆箱

此时代码也没有安分,你可以看到:
在这里插入图片描述
意思是使用Float的原始形态float就可以了,这是因为我们还没有用Float进行任何操作,是正常现象

包装类还有一个非常使用的部分,即字符串转化,在输入一个字符串时,可以很方便的将该字符串转为你想要的类型:
int x = Integer.parseInt(“123”);
float y = Float.parseFloat(“12.23”);
boolean z = Boolean.parseBoolean(“false”);

特别注意:转化过程中如果传入abc强行转为int依然会出错,boolean的转化只有输入ture(无视大小写)才会返回true,其他情况都是false)

异常处理

异常指在程序中导致程序中断的一种指令流,在异常发生时,程序将会中断,所有后续程序都无法执行。
在Java中,当产生异常时,实际上是Java自动产生了一个异常类的对象,我们想要对异常进行处理,让程序继续运行下去,则需要捕获该异常

Java中有很多异常类,而异常的顶级父类是Throwable类,其有两个子类分别为error类和Exception类,Exception类又有一个主要子类RuntimeException。

在这里插入图片描述

如果出现Error类的异常,即Java认为你无法解决的错误,大多和硬件有关,无法通过代码解决,只能考虑避免(如内存不足)
而Exception类中的异常类,是受检异常,就是这种异常在编译时就会出现错误提示,提示你这里有问题;其中的RuntimeException又叫做非受检异常,即运行时可能发生的错误

try-catch

在之前我讲过简单的异常处理,现在我们来学习更高级的异常处理方式try-catch:

try{
    // 可能产生异常的代码段
}catch(异常类型1 对象名1) {
    // 异常的处理操作1
}catch(异常类型2 对象名2) {
    // 异常的处理操作2
}...
finally{
    // 异常的统一出口
}

当try语句中产生异常时,系统会自动产生一个异常类的实例化对象,并且自动找到匹配的catch语句,所有的catch根据方法的参数匹配异常类的实例化对象(所以你必须知道会出现什么样的错误),如果匹配成功,则立即进行catch中的代码
在进行异常的处理之后(无论是否有异常),会执行finally中的代码(除非使用System.exit(0);强制结束),即使在之前的catch中return了,也会先执行finally中的代码再进行return(return的部分会被储存,finally不能改变return的值,但是如果是return一个对象中的属性,finally可以改变该属性)

让我们看一段代码

import java.util.Scanner;

public class Exception {
    public static void main(String[] args){
        
        Scanner scanner = new Scanner(System.in);
        int a = 120;
        int b = scanner.nextInt();
        
        System.out.println(a / b);
        System.out.println("1");
    }
}

这一整段代码都不会有任何错误提示,但是在运行时可能出现两种异常,一是你输入了一个非int类型的参数,二是你输入了0,无论哪一种,都会立即使该程序停止,后面的1也不会被输出
我们分别进行错误操作,就可以看见错误的原因
在这里插入图片描述
在这里插入图片描述
所以我们用try-catch将这段代码进行处理

public class Exception {
    public static void main(String[] args){

        Scanner scanner = new Scanner(System.in);
        int a = 120;
        try {
            int b = scanner.nextInt();
            System.out.println(a / b);
            System.out.println("Run successfully");
        }
        catch (InputMismatchException e){
            System.out.println("Please input an integer");
        }
        catch (ArithmeticException e){
            System.out.println("Divisor cannot be 0");
        }
    }
}

这时无论怎么输入,整个程序都不会崩溃,在出现错误的时候还能继续运行并且输出错误的原因(finally可以省去,catch也可以省去,但是两者必须存在至少一个)

当然我们也可以省略一点,将多个catch合并为一个,这时报错并不会显示具体错误原因,只是告诉你出错了(使用Exception类也是一样)
特别注意:如果想要使用Exception必须写为java.lang.Exception)

        catch (RuntimeException e){
            System.out.println("Error");
        }

JDK7以后也有这种方式,这种方式并不实用,了解即可

        catch (InputMismatchException | ArithmeticException e){
            System.out.println("Error");
        }

throws

throws是给方法的声明的使用,意为不处理该异常,而是将方法抛出去给调用方法的地方,如果抛到最后没有try-catch方法捕获该异常,最后还是会异常终止程序(在出现异常后,后面的代码同样无法被执行)

通过如下方式使用:

返回值 方法名称() throws Exception{
    // 方法体
}

其中也可以使用Exception类的子类,如RuntimeException,IOException等等

在程序中也可以使用throw直接抛出异常
throw new Exception(“抛出异常”);

使用该方法相当于主动生成一个异常并抛出,其后面的代码无法被执行

自定义异常类

在之前Object类中,可以通过重写的方式更改默认的输出和判断,在异常类中也可以通过继承现有的异常来构建自定义异常

如果编写一个类继承Exception,并重写一参构造方法,便可以自己定义一个受检类型异常;而继承RuntimeException则是不受检类型异常

可变参数方法和递归

可变参数方法

在创建方法时,如果你不知道传入参数的多少,可以使用一个可变参数方法,无论传入多少参数都可以运行(甚至不传),注意可变参数的部分只能出现在参数列表的最后


返回值类型 方法名称(参数类型... 参数名称){
    // 方法体,传入的参数通过数组形式调用
}
int getSum(int... nums){
   int sum = 0;
   for(int i = 0; i < nums.length; i++) {
       sum += nums[i];
   }
   return sum;
}

但是很尴尬的是不定参方法并没有被广泛使用,和三目运算符一样,虽然很简便,但是并不是不可或缺,而且还被认为破坏了代码逻辑的浪漫

递归

递归是一个算法中的概念,在计算机领域中通常被认为是一个方法调用其自身

让我们先来认识认识递归:

首先我们定义一个数列an=2 * n
那么an的前几项为2,4,6,8,10,12…

如果使用递归的思想,那么an=2 + an-1且a1=2,an的所有项并都没有改变,但是获取an的方法改变了,这就是递归的意义

定义an的代码可以这样定义:

    int getAn(int n){
        int an = 2 * n;
        return an;
    }

那么使用递归就是:

    int getAn(int n){
        int an = 2 + getAn(n - 1);
        return an;
    }

编写时不会报错,但是当我们开始运行,瞬间报错了,错误原因是
Exception in thread “main” java.lang.StackOverflowError
即栈内存溢出了,因为这个程序一旦开始运行就停不下来了,内存当然会溢出

所以我们应该给他额外写一个判断,正如之前定义an时要补充a1=2

    int getAn(int n){
        int an;
        if(n == 1 )
            an = 2;
        else
            an = 2 + getAn(n - 1);
        return an;
    }

当然你可能会发现,递归不仅逻辑复杂,而且对于内存的使用更是远大于循环,所以其实递归也是一个被抛弃的设定(所以跟变参方法放在一起讲了)。在平常的项目中能使用循环的一定要用循环,不到万不得已,不推荐使用递归

转载请注明出处

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值