2024蓝旭春季培训预习(二)—— JAVA异常类+常用类+容器、范类

异常类

在运行运行java的程序的时候,无法避免的我们会遇到一些玩报错,而这些报错我们大致可以将他分为两类,一种是Exception,还有一种就是Error。

在java的程序中,我们可以处理部分报错,使程序可以向着另一个方向正常的运行,这种可以解决的报错其实就是Exception的类型,也就是我们要讲的异常类。

初识异常类

除数为0

索引越界

访问null对象

错误出现时间

我们可以发现这些异常都是在运行时出的错,什么叫做运行时出现的错误,我们可以拿最后一个例子来举例,像是:

运行时错误

这说明了程序刚开始是可以运行的,但是在某一个节点出现了问题,从而报错无法进行了。

编译时错误

像是同样的代码,我将println少打了一个n,这个程序就无法编译了,所以还没运行就报错停止了。

我们处理异常处理的就是在运行时出现的错误。而且异常的种类有很多,不同种类的异常具有不同的含义,也有不同的处理方式。

捕获

就像我们之前所说的那样,我们可以通过一些方法来避免这些异常的出现,首先我们就可以通过捕获来处理异常。

结构

我们通常用try-catch-final来实现捕获。主要的结构是一下这样的:

try{
    可能会出现异常的语句;
}
catch(相应的异常){
    对应手段;
}
finally{
    异常的出口;
}

其中的的finally主要是用于清除本地残留不需要的东西,来释放空间的,像是reader.close()来关闭输入端,不做过多讲解。

解决单个异常

接下来我们对应之前的实例,一一解决他们的异常:

从上面的代码中我们可以看出,这个程序我们即使遇到了一些异常,但是我们仍然可以继续去运行我们的程序,虽然我们在try里面的程序被掐停了,但是我们在能够正常运行了程序外的输出语句,可见我们成功的防止了程序遇到异常时就退出运行的情况。

其中的e.printStackTrace()是打印了调用栈中出现异常的位置和状况。

相同的方法我们也可以处理其他的几个异常,只需要将catch中的异常进行更换即可。

解决多个异常

当然我们还可以一口气对于多个代码监测他们的多种的异常出现情况,正如下图一样:

统一解决所有Exception

我们还可以通过Exception的方法来检测所有的异常错误,因为Exception是所有异常的父类,因此能够检测的到。

抛出

抛出顾名思义就是我们人为的抛出一个异常,我们通常用throw来直接抛出我们异常。可是既然编译器能够自动识别异常,那么我们为什么要自己主动抛出异常呢?

其实有些情况下,我们不得不提前抛出这个异常才可以,因为不是所有的异常都报错在运行时,像是CloneNotCupportedException这个异常类是报错在编译期间的,所以我们要保证这个程序的运行,我们就得主动的抛出这个异常,使得程序正常运行。

throw

        int a,b;
        Scanner reader = new Scanner(System.in);
        a=reader.nextInt();
        b=reader.nextInt();
        try {
            if (b == 0) {
                throw new ArithmeticException();
            }
            System.out.println(a / b);
        } finally {
        }

这就是简单的应该主动抛出异常,当然我们也可以用catch来捕捉这个异常,这里只是他的简单的打发,不必讲究太多。

throws

throws是添加在方法上面的,正如如下:

    public double divide(double a,double b) throws ArithmeticException
    {
        if(b==0)
        {
            throw new ArithmeticException();
        }
        return a/b;
    }

这种加在方法上的异常是为了提醒调用者,将有可能出现的异常,并提前将其列出。

还有我们可以看出我们在throw的时候new了这个异常类,因为异常类也算是类,所以我们要使用的话还是得为其开辟相应的空间的。

自定义异常

刚刚上面说了异常也相对的是类,所以我们如果想要自己自定义一种类的话,我们必须继承我们相应的父类。结合我们上节课所学习的知识,我们可以写出一下的代码:

class MyException extends Exception{
    public MyException() {
    }

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

我们可以直接继承最为根部的Exception。

可以配合我们主动抛出来实现相应的自己想要的功能,就比如我们可以在登入失败的时候直接进入抛出错误,防止他人恶意侵入,保证了其安全性。

特殊类型

包装类

共性

基础数据类型不是类,不能直接当作类型来实现,因此Java将这些基本数据类型进行了包装,其中Integer和Charater类型与基本数据类型的名称不同。

并且除了Boolean和Character,其他六种的包装类都继承自Number类

我们还可以通过相应的函数,来进行对字符串转换相应类型的功能,我们以整型为例来写一段代码:

Integer i=Integer.parseInt("11");

从上面的代码我们可以看出parseInt是直接加在类型的后面的,可见这是一个static修饰的类方法,只能通过类来进行调用,除了Character其他的包装类都具有这种方法。

我们也可以通过方法toString来转换会字符串,写法相似。

Byte

Byte类型有自己独有的转换中字符大小写的功能,比如转换大写就是toUpperCase(),小写则是将Upper换成Lower。

还有属于判断类型的isDigit(),isLetter(),还有对应吧上面的to改成is的大小写判定,这些其实都非常实用。

String

String是Java里面非常常见的一种包装类,其是我们所熟知的字符串类型,正如我们刚刚在上面提及到的包装性转换String类型。

String还有像是直接拼接,和查询对应位置的字符,转换字符数组等功能。

buffer

string的buffer类型和string不太一样,我们平时操作string的时候会发现,我们无法直接对string里面的元素进行更改,每一次操作都是创建了一个新的string。而StringBuffer支持对于一个单个字符进行修改,且可以和String类型互相转换,但是不像String类型声明,必须通过new来创建新的对象,毕竟同样是类。

String str;
StringBuffer stringbuffer = newe StringBuffer(str);

也可以用append方法来进行进行追加字符串。

public StringBuffer replace(int start,int end,String str)//这是替换的方法,我们可以将从start位置上面的字符一直到end上的进行替换,如果是超出范围的也会替换

从上面的样例中我们可以看出无论start和end指示在哪里,replace都可以将中间的字符进行替换。

还有像是寻找子符的indexOf和删除delete,不一一进行举例了。

builder

总体上和buffer基本相同,如果将String和StringBuffer还有StringBuilder进行比较的话,Buffer增删的效率较快,线程较为安全,而Builder的话他的效率是最高的,但是他的线程叫Buffer没有那么安全,而像是String的话,他每一次增删和修改都会在内存中再创造一个String项目来存储,所以会造成很大的浪费,如果增删频繁的话不推荐使用String。

BigDecimal

加减乘除

BigDecimal这个类型是一种可以不限制小数位多少位的一种类型,他可以进行加减乘除等方法,都是以他的英文名进行命名的,然后用BigDecimal来进行接收。

传值

我们主要可以通过传入各种类型的值来进行的值来构造BigDecimal,但是要注意BigDecimal当接收double类型的数的时候可能会造成精度损失的问题,所以我们最好是通过String类型来进行构造。

我们还可以用valueOf来进行创建值,因为其底层是将数字转换成String类型来进行赋值的,所以我们可以很好的保证其精度,但是我们依然无法存入超过double类型的数字。

但是等值的时候我们不能使用equals来进行比较,而是应该用compareTo。

舍入方式

BigDecimal还提供了相应的舍入的方式,但是由于其方式较多,我们不一一展示,我们讲一下主要用到的BigDecimal.setScale()方法用于格式化小数点,只需将要精确的小数个位数写进去即可,其他方式只需要对应填入一些对应的语句就行了

    BigDecimal b1 = new BigDecimal("1.0");
    BigDecimal b2 = new BigDecimal("1.00");
    System.out.println(b1.equals(b2));
    System.out.println(b1.compareTo(b2));
false
0
格式化输出

我们可以从上面代码中看出我们定义了一种DecimalFormat的格式化方法,#就是可以舍去的部分,逗号就是相应的分割位置。

其他类型

泛型

所谓的泛型其实就是可以在运行的时候再规定放什么具体类型的一种类型,这样我们就可以按照运行时的需求进行改变。就像下面这样:

class MyArrays<T>

其中在<>的T就是所谓的范类,我们在类的开头先声明了这个泛型,之后在声明和返回值上我们就可以用所谓的T来进行一个替换,这样我们就不会出现像是Object需要强制转换的问题,而是只用T就可以来替代我们想要的任何类型数据。

泛型实例

但是我们要注意的是我们要声明一个T类型的变量得这么声明:

public T[] objects = (T[])new Object[10];

因为在这个时候T尚未被实例化,我们并不知道T具体是什么东西,因此无法给T分配相应的内存进行创建Object,只能用强转的方式来进行开辟空间。

以上是针对于泛型数组和实例的创建而言的,接下来我们具体讲讲泛型类。

泛型类

根据上面的类型创建,我们会自然的知道泛型类的实例是如何创建的:

MyArray<Integer> list = new MyArray<Integer>();

但是需要注意的是泛型其实只接受传入实际的类型,因此基本数据类型无法传入,但是我们可以使用它的包装类。

泛型的上界

对于将要传入的值,我们有时不希望他什么都传入,因此我们可以使用继承来进行限制,就像这样:

class MyArray<T extends Number>

比如这个例子,我们就很好的讲T限制为了是Number的子类,当然这里Number我们可以设置为我们想要的任何一种父类,来保证我们传入的类型是我们所想要的类型。

通配符

当我们实际在运行代码之前,我们也许并不知道我们的方法将要传入什么样子的类型,就像这样子:

我们先定义了一个My的泛型类:

然后我们运行我们的主函数:

可以看见很好,什么问题都没有,但是实际上我们在编写的时候并不知道我们func这个方法里面该传入什么样子的一个值,假如我写错的话会发生什么事情呢?

可以看见我们的my马上就标红了,因为传入的参数类型是不一样的,我们又不能在定义func函数里面写上我们之前的T,因为他们既不是 在一个类文件里面,他们也没什么关系,所以func是无法识别T的。这个时候我们就要拿出我们的通配符了。

通配符其实就是一个?,我们只需要在<>里面加入?,我们就可以很好的解决这个问题了。

这样子我们就又能运行了。

通配符也有他自己的上下界 ,我们只需要在想要上界的时候加入extends,在需要下界的时候加入super即可。

列表

列表是十分常见的一种储存方式,我们不过多介绍,直接来进行实例展示:

List<String> list = new ArrayList<>();

这样子我们就声明了一个String类型的一个列表。

我们可以通过add进行添加,remove进行删除,set进行修改,和其他语言类似,不做过多的介绍。有必要可以自己去搜索(写累了,不想写了)。

set

类似于c++的stl库中的集合,不能存储相同的元素,用法同上。

map

就是字典,一组键值对,用法不多赘述。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值