图灵日记之java奇妙历险记--异常包装类泛型

news2024/12/29 9:04:08

目录

  • 异常概念与体系结构
    • 异常的分类
    • 异常的处理
      • 防御式编程
      • 异常的抛出
      • 异常的捕获
        • 异常声明throws
        • try-catch捕获并处理
    • 自定义异常类
  • 包装类
    • 基本数据类型及其对应包装类
    • 装箱和拆箱
  • 泛型
    • 泛型使用
      • 类型推导
    • 裸类型
      • 说明
    • 泛型的编译机制
    • 泛型的上界
      • 语法

异常概念与体系结构

在java中,将程序执行过程中发生的不正常行为称为异常

异常的分类

异常可能在编译时发生,也可能在程序运行时发生,根据发生的时机不同,可以将异常分为:

  1. 编译时异常
    在程序编译期间发生的异常,称为编译时异常,也称为受检查异常
  2. 运行时异常
    在程序执行期间发生的异常,.称为运行时异常也称为运行时异常
    编译时出现的语法性错误,不能称为异常

异常的处理

防御式编程

错误在代码中是客观存在的,因此我们要让程序出现问题及时报错

  1. 在检查前做好充分的检查:事前防御型
    缺陷:正常流程和错误处理流程代码混在一起,代码显得乱
  2. 先操作,出现问题再处理
    优势:正常代码与错误代码分离开
try{
//可能报错的代码
}catch (捕获具体异常) {
}finally {
}

在Java中,处理异常主要的5个关键字:throw,try,catch,final,throws

异常的抛出

如何抛出异常?

  1. 程序触发
  2. throw抛出异常
    在Java中借助throw关键字,抛出指定的异常对象,手动抛出异常,一般用于抛出自定义的异常
throw new XXXException("异常原因");

注意:

  1. throw必须写在方法内部
  2. 抛出的对象必须是Exception或Exception的子类对象
  3. 如果抛出RunTimeException或其子类,则可以不处理,留给JVM处理
  4. 抛出编译时异常要自己解决,否则无法通过编译
  5. 异常一旦抛出,后面的代码将不会执行

异常的捕获

异常的捕获,也就是异常的处理方式,主要有两种,一种是try-catch捕获处理,另一种是异常声明throws

异常声明throws

使用在方法声明之后
告诉使用者这个方法会出现XX异常
如果一个方法内部存在一个编译时异常(受查异常),此时这个编译时异常一定要进行处理,目前的处理方式是在方法定义后面加上throws来声明该异常,该异常会留给JVM来处理

处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给方法的调用者.即当前方法不处理,提醒方法调用者处理异常

语法格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2... {
}

注意:

  1. throws必须在方法参数之后
  2. 声明的异常必须是Exception或者Exception的子类
  3. 方法内部如果抛出多个异常,throws之后必须跟多个异常类型,用逗号隔开,存在父子关系的,声明父类即可
  4. 调用声明抛出异常的方法,调用者必须对该异常进行处理,或者继续使用throws抛出
    throws抛出交给JVM处理,一旦交给JVM处理,程序就会异常终止
try-catch捕获并处理

throws并没有对异常进行处理,而是把异常报给了使用者,需要使用者进行处理.真正要对异常进行处理,要用try-catch

        System.out.println("1");

        System.out.println(1/0);

        System.out.println("2");

在这里插入图片描述
使用try-catch,catch里面的参数就是你要捕获的异常,如果捕获到了才会执行catch当中的内容

        System.out.println("1");

        try {
            System.out.println(1/0);

        } catch (ArithmeticException e) {
            System.out.println("处理异常1");
        }

        System.out.println("2");

在这里插入图片描述
如果存在多种异常,使用catch多个捕获
可以使用printStackTrace来具体追踪异常的位置

        System.out.println("开始");
        try {
            int[] arr = new int[5];
            System.out.println(arr[10]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("异常处理");
            e.printStackTrace();
        }
        System.out.println("结束");

在这里插入图片描述
打印的顺序好像不大对,printStackTrace的底层代码是使用其他的工具来打印的,可能运行时间不同,导致前后顺序不对

        try {
            int[] arr = new int[1];
            System.out.println(arr[10]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("处理异常");
        } catch (ArithmeticException e) {
            System.out.println("处理异常");
        }

多次使用catch来捕获多个异常,也可以如下

        try {
            int[] arr = new int[1];
            System.out.println(arr[10]);
        } catch (ArrayIndexOutOfBoundsException |ArithmeticException e) {
            System.out.println("处理异常");
        }

当在try中捕获到异常后,直接调转到catch,不会执行后面的代码,如下:

        try {
            int[] arr = null;
            System.out.println(arr[0]);
            System.out.println("abc");
        } catch (NullPointerException e) {
            System.out.println("处理异常");
        }

在这里插入图片描述
关于异常的处理方式
异常种类很多,取决于业务场景
对于比较严重问题(和钱相关的场景),让程序直接崩溃
对于不大严重的问题(大多数情形下),记录错误并通知
对于可能会回复的问题(和网络有关问题),可以尝试再次连接
注意

  1. try内部抛出异常之后的代码不会再执行
  2. 如果抛出异常与catch时类型不匹配,异常不会被捕获,也不会被处理,继续抛出,直到被JVM接收后中止程序
  3. try可能抛出多个异常对象,必须使用多个catch来捕获
    虽然能够捕获多个异常,但是同一时刻只能抛出一个异常
        try {
            int[] arr = null;
            System.out.println(arr[0]);
            System.out.println("abc");
        } catch (Exception e) {
            System.out.println("处理异常");
        } catch (NullPointerException e) {
            System.out.println("处理异常");
        }

不能使用父类来接受子类异常,会导致异常不精准
可以让父类在子类之后充当垫底的作用,但是放在子类之前子类将不会执行,因为子类能捕获的异常,父类一定能捕获

        try {
            int[] arr = null;
            System.out.println(arr[0]);
            System.out.println("abc");
        } catch (NullPointerException e) {
            System.out.println("处理异常");
        } catch (Exception e) {
            System.out.println("处理异常");
        }
public static void main(String[] args) {
        System.out.println(mtd());
    }
    public static int mtd() {
        try {
            int[] arr = null;
            System.out.println(arr[0]);
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        } finally {
            System.out.println("执行finally");
        }
        return 1;
    }

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println(mtd());
    }
    public static int mtd() {
        try {
            int[] arr = new int[10];
            System.out.println(arr[0]);
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        } finally {
            System.out.println("执行finally");
        }
        return 1;
    }

在这里插入图片描述
finally的代码无论是否捕获异常一定会被执行

    public static void main(String[] args) {
        System.out.println(mtd());
    }
    public static int mtd() {
        try {
            return 0;
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        } finally {
            System.out.println("执行finally");
        }
        return 1;
    }

在这里插入图片描述
即便try的内容中已经返回,但是仍旧会执行finally中的内容
所以finally里的内容一定会被执行
一般用来释放资源
语法格式

try{
}catch(捕获的异常) {
//try抛出的异常与捕获的异常一致或是try中抛出的异常的父类
}finally{//一定会被执行
}

//后续代码
//异常被捕获,异常处理,此处代码执行
//如果不活了,但是类型不匹配,就没有捕获到,此处不会执行

异常处理流程:
程序先执行try中的代码
如果try中的代码出现异常,就会结束try中的代码,看和catch中的异常类型是否匹配
若未找到匹配类型,就会将异常向上传递给上层调用者
若找到则执行catch内容
无论是否匹配异常类型,finally内容都会执行
如果上层调用者也没有处理异常,就继续向上传递
一直到main方法也没有合适的代码处理异常就会交给JVM处理,程序终止

自定义异常类

如果要写一个自定义异常,一定要继承一个异常
extends Exception 编译时异常
extends RuntimeException 运行时异常
具体方式:

  1. 自定义异常类,然后继承自Exception或者RunTimeException
  2. 实现一个带有String类型参数的构造方法,参数函数:写出异常原因

包装类

在java里,因为基本类型不继承于Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了一个包装类型

基本数据类型及其对应包装类

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

装箱和拆箱

基本类型转变为包装类型

    public static void main(String[] args) {
         Integer a = 0;
         int b = 1;
         Integer c = b;
        System.out.println(a);
    }
    public static void main(String[] args) {
        Integer a = 1;//装箱  自动装箱
        
        Integer b = Integer.valueOf(2);//显示装箱
    }

拆箱

    public static void main(String[] args) {
        Integer a = 1;
        int b = a;//自动拆箱

        int c = a.intValue();//显示拆箱
        System.out.println(b);
    }
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a==b);

        Integer aa = 200;
        Integer bb = 200;
        System.out.println(aa==bb);
    }

在这里插入图片描述
再看valueOf源码
在这里插入图片描述
IntegerCache.low是-128
IntegerCache.high是127
当i处理[-128,127]中时,i是放进了一个数组,当超出这个范围是产生一个新的对象,产生新的地址,打印时比较的是地址所以返回false

泛型

泛型:适用于多种类型
针对代码而言就是对类型实现了参数化
泛型的主要目的:指定当前容器,要持有什么类型的对象.让编译器去检查
实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值?

class Generics {
    public Object[] arr = new Object[10];

    public void PushArray(int pos, Object o) {
        arr[pos] = o;
    }

    public Object GetArray(int pos) {
        return arr[pos];
    }
}

实现代码如上
任何类型都可以存储

    public static void main(String[] args) {
        Generics generics = new Generics();
        generics.PushArray(0,1);
        generics.PushArray(1,"abc");
        String c = (String) generics.arr[1];
        System.out.println(c);
    }

数组下标1的类型String需要强制类型转换

 
public class Test {
    public static void main(String[] args) {
        Generics<Integer> generics = new Generics<Integer>();
        generics.PushArray(0,1);
        generics.PushArray(1,2);

        Generics<String> generics1 = new Generics<String>();
        generics1.PushArray(0,"abc");
        generics1.PushArray(1,"efg");
    }
}

class Generics<T> {
    public Object[] arr = new Object[10];

    public void PushArray(int pos, T o) {
        arr[pos] = o;
    }

    public T GetArray(int pos) {
        return (T)arr[pos];
    }
}

泛型就是将类型进行传递

class 泛型类名称<类型形参列表>{
	//这里可以使用类型参数
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
  // 这里可以使用类型参数
}

泛型使用

泛型类<类型实参> 变量名;//定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参);//实例化一个泛型类对象

泛型只能接收类,所有基本类型必须使用包装类

类型推导

当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写

        Generics<Double> arr = new Generics<>();

裸类型

说明

裸类型是一个泛型类但没有类型实参

        Generics array = new Generics();

小结

  1. 泛型是将数据类型参数化,进行传递
  2. 使用表示当前类是一个泛型类
  3. 泛型目前的优点:数据类型参数化,编译时自动进行类型检查和转换

泛型的编译机制

    public T[] arr = new T[10];

不能new泛型类型数组

泛型是编译时期存在的,当程序运行起来,到JVM之后,不存在泛型这一概念了

泛型在编译的时候是如何编译的呢?
擦除机制.擦除成了Object

观察字节码文件
在这里插入图片描述

为什么不能实例化泛型类型数组?

 public T[] array = (T[])new Object[10];
 public T[] getArray() {
    return array;
 }

替换后的方法:

public Object[] getArray() {
  return array;
}

返回的Object数组里面可能存放不同的数据类型,直接转给某一个类型的数组可能无法转换

泛型的上界

在定义泛型类时,有时需要传入的类型变量做一定的约束,可以通过类型边界来进行约束

语法

class 泛型类名称<类型形参 extends 类型边界> {
 ...
}
public class Test {
    public static void main(String[] args) {
        Generics<Number> generics = new Generics<>();
        Generics<Integer> generics1 = new Generics<>();
        Generics<Double> generics2 = new Generics<>();
        
        Generics<String> generics3 = new Generics<>();//此处报错,String的父类不是Number
    }
}
//T一定是Number或者Number的子类
class Generics<T extends Number> {

}
class Person {

}

class Student extends Person {

}

class Generics2<T extends Person> {

}

public class Test {
    public static void main(String[] args) {
        Generics2<Student> generics21 = new Generics2<>();//Student的父类是Person
        Generics2<Person> generics22 = new Generics2<>();//是Person类
        Generics2<Integer> generics23 = new Generics2<>();//报错,Integer的父类并非Person
    }
}

写一个泛型类,求数组最大值,如下


class Ag<T> {
    public T FindMax(T[] arr) {
        T max = arr[0];
        for (int i = 1; i < arr.length; i++) {
        //报错
            if(max < arr[i]) {
                max = arr[i];
            }
        }
        return max;
    }
}

T一定是引用数据类型,引用数据类型比较大小要告诉编译器比较什么,上段代码中未指定
而且你的T 被擦除成了一个Object类,Object类中也没有比较的接口,不能比较,如下图
而你又要得到最大值的话,你的T类型一定要是可以比较的
在这里插入图片描述

所以:我们要如何让这个T一定可以进行比较呢?
在这里插入图片描述
进行这样修改,并不是说T一定要继承Comparable接口,意思是将来你指定的泛型类传入的参数一定是实现了Comparable接口
T一定是实现了Comparable接口的
Comparable接口有比较的方法
在这里插入图片描述


class Ag<T extends Comparable<T>> {
    public T FindMax(T[] arr) {
        T max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(max.compareTo(arr[i]) < 0) {
                max = arr[i];
            }
        }
        return max;
    }
}
public class Test {
    public static void main(String[] args) {
        Ag<Integer> ag = new Ag<>();//未报错Integer实现Comparable接口
        Ag<Person> ag1 = new Ag<>();//报错,Person类未实现Comparable接口
    }
}
class Person {

}

在这里插入图片描述


public class Test {
    public static void main(String[] args) {
        Ag<Integer> ag = new Ag<>();
        Ag<Person> ag1 = new Ag<>();
    }
}
class Person implements Comparable<Person>{
    @Override
    public int compareTo(Person o) {
        return 0;
    }
}

当你的Person实现了Comparable接口后,就不会报错了

    public static void main(String[] args) {
        Ag<Integer> ag = new Ag<>();
        Integer[] integers = {1,2,3,4,5,6};
        Integer res = ag.FindMax(integers);
        System.out.println(res);
    }

在这里插入图片描述


public class Test {
    public static void main(String[] args) {
        Ag2 ag2 = new Ag2();
        Integer[] integers = {1,2,3,4};
        Integer res = ag2.FindMax(integers);
        System.out.println(res);
    }
}

class Ag2 {
//泛型方法
    public<T extends Comparable<T>> T FindMax(T[] arr) {
        T max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(max.compareTo(arr[i]) < 0) {
                max = arr[i];
            }
        }
        return max;
    }
}

没有传入类型,编译器是如何识别类型进行比较得到最大值的?
类型推导:根据实参传值来推导此时的类型

在这里插入图片描述
这样写也可以,可以直接推导出类型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《SPSS统计学基础与实证研究应用精解》视频讲解:SPSS数据排序

《SPSS统计学基础与实证研究应用精解》4.6 视频讲解 视频为《SPSS统计学基础与实证研究应用精解》张甜 杨维忠著 清华大学出版社 一书的随书赠送视频讲解4.6节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。本书旨在手把手教会使…

智能机器人与旋量代数(9)

Chapt 3. 螺旋运动与旋量代数 3.1 螺旋运动 螺旋运动是关于一条空间直线的一个旋转运动&#xff0c;并伴随沿此直线的一个平移。是一种刚体绕空间轴 s s s旋转 θ \theta θ角&#xff0c;再沿该轴平移距离 d d d的复合运动&#xff0c;类似螺母沿螺纹做进给运动的情形。 一…

x-cmd pkg | dasel - JSON、YAML、TOML、XML、CSV 数据的查询和修改工具

目录 简介首次用户快速实验指南基本功能性能特点竞品进一步探索 简介 dasel&#xff0c;是数据&#xff08;data&#xff09;和 选择器&#xff08;selector&#xff09;的简写&#xff0c;该工具使用选择器查询和修改数据结构。 支持 JSON&#xff0c;YAML&#xff0c;TOML&…

SQL提示与索引终章

✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL-进阶篇 &#x1f4dc; 感谢大家的关注&#xff01; ❤️ 可以关注黑马IT&#xff0c;进行学习 目录 &#x1f680;SQL提示 &#x1f680;覆盖索引 &#x1f680;前缀索引 &…

科技、文化与旅游的融合创新:智慧文旅的未来之路

在当今社会&#xff0c;科技、文化与旅游的融合已经成为文旅产业转型升级的重要趋势。这种融合不仅有助于提升文旅产业的核心竞争力&#xff0c;更有助于推动产业的数字化转型和可持续发展。 本文将深入探讨科技、文化与旅游的融合创新&#xff0c;以及智慧文旅场景的解决方案…

Unity3d引擎中使用AIGC生成的360全景图(天空盒)

前言 在这里与Skybox AI一起&#xff0c;一键打造体验无限的360世界&#xff0c;这是这个AIGC一键生成全景图的网站欢迎语。 刚使用它是23年中旬&#xff0c;在没有空去给客户实地拍摄全景图时&#xff0c;可以快速用它生成一些相关的全景图&#xff0c;用作前期沟通的VR de…

【第十四课】并查集(acwing-837连通块中点的数量 / c++代码 / 思路详解)

目录 思路 代码如下 一些解释 思路 由于这道题是在并查集这个知识点下面&#xff0c;所以自然我们直接将无向图及之间连线的表示模型化为我们并查集的模板(或许其实也并不难想到?)&#xff0c;要解释一下的话就是&#xff1a;我们将无向图中的每个顶点当作一个集合&…

JSON简单了解

文章目录 1、JSON介绍2、ES6模版字符串3、JS对象转化为JSON字符串3.1、手动JS对象转化为JSON字符串3.2、自动JS对象转化为JSON字符串 4、JS对象和java互相转换 1、JSON介绍 JSON 概念&#xff1a;JavaScript Object Notation。JavaScript 对象表示法&#xff0c;简单理解JSON是…

C++参悟:数值运算相关

数值运算相关 一、概述二、常用数学函数1. 基础运算1. 浮点值的绝对值&#xff08; |x| &#xff09;2. 浮点除法运算的余数3. 除法运算的有符号余数4. 除法运算的有符号余数和最后三个二进制位5. 混合的乘加运算6. 两个浮点值的较大者7. 两个浮点值的较小者8. 两个浮点值的正数…

个人云服务器docker搭建部署前后端应用-myos

var code "87c5235c-b551-45bb-a5e4-9593cb104663" mysql、redis、nginx、java应用、前端应用部署 本文以单台云服务器为例&#xff1a; 1. 使用腾讯云服务器 阿里或其他云服务器皆可&#xff0c;类似 安装系统&#xff0c;现在服务器系统都集成安装了docker镜像&a…

仓库管理系统

仓库管理系统 项目环境要求 1.设备支持&#xff1a;Windows7、Windows8或Windows10&#xff1b; 2.数据库&#xff1a;Mysql 8.0&#xff1b; 3.软件支持&#xff1a;eclipse、navicat 需求分析 需求分析阶段的根本任务是要明确仓库管理系统功能需求&#xff0c;以便提出整个系…

Mapbox加载浙江省天地图服务和数据处理

1. 加载影像服务 通过浙江省天地图官网申请所需服务&#xff0c;使用token获取服务数据 由于浙江省天地图使用的坐标系是 cgcs2000&#xff0c;需要使用 的框架对应为 cgcs2000/mapbox-gl&#xff0c;通过cdn引入或npm下载 影像服务地址为&#xff1a; ‘https://ditu.zjzw…

2024年 复习 HTML5+CSS3+移动web 笔记 之CSS遍

第一天第二天第三天 1.1 引入方式 1.2 选择器 1.3 画盒子 1.4 文字控制 1.5 综合案例 一 新闻详情 2.1 复合选择器 2.2 伪类选择器 2.3 CSS 特性 2.4 Emmet 写法 2.5 背景属性 2.6 显示模式 2.6 综合案例 一 热词 &#xff08;设计稿&#xff1f;&#xff09; 2.7 综合案例 一…

优化用户体验测试应用领域:提升产品质量与用户满意度

在当今数字化时代&#xff0c;用户体验测试应用已经成为确保产品质量、提升用户满意度的关键工具。随着技术的不断发展&#xff0c;用户的期望也在不断演变&#xff0c;因此&#xff0c;为了保持竞争力&#xff0c;企业必须将用户体验置于产品开发的核心位置。本文将探讨用户体…

耳鸣是怎么回事呢?

什么是耳鸣&#xff1f; 耳鸣是指在没有任何客观声响的情况下&#xff0c;个人主观上却感觉听到声音&#xff0c;有些人甚至觉得声音来自头部。耳鸣的感觉因人而异&#xff0c;声音多种多样。比如明明没有开任何电器&#xff0c;但却可以感觉到电流声&#xff0c;明明旁边没有…

如何使用固定公网地址访问多个本地Nginx服务搭建的网站

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 本文主要介绍如何在Windows系统对Nginx进行配置&#xff0c;并结合cpolar内网穿透工具实现固定公网地址远程访问多个本地站…

leaflet学习笔记-带过滤的图例(九)

前言 图例不只能够帮助我们在查看地图的时候更加方便容易地分辨不同颜色代表的要素&#xff0c;本文要介绍的图例组件还可以按需求过滤掉不用显示的要素&#xff0c;使地图的更能清晰的显示我们需要显示的内容 技术核心 说到过滤要素&#xff0c;第一时间想到的就是滑块组件…

burp靶场--业务逻辑漏洞

burp靶场–业务逻辑漏洞 https://portswigger.net/web-security/logic-flaws#what-are-business-logic-vulnerabilities ### 什么是业务逻辑漏洞&#xff1f; 业务逻辑漏洞是应用程序设计和实现中的缺陷&#xff0c;允许攻击者引发意外行为。这可能使攻击者能够操纵合法功能来…

德思特干货|如何使用SBench 6对数字化仪采集信号进行处理?(三)——快速傅立叶变换(FFT)

来源&#xff1a;德思特测量测试 德思特干货&#xff5c;如何使用SBench 6对数字化仪采集信号进行处理&#xff1f;&#xff08;三&#xff09;——快速傅立叶变换&#xff08;FFT&#xff09; 原文链接&#xff1a;https://mp.weixin.qq.com/s/mYS1iDXFNVfReCGGtF78mw 欢迎关…

Ubuntu用gparted重新分配空间

ubuntu系统使用过程中安装系统时预先留的空间不够使用怎么办&#xff1f; 这么办&#xff01; 首先 使用df -h 查看当前空间使用情况 已经分配的空间重新规划 &#xff1f; 先将已分配的空间中的多余空间分离出来&#xff1b; 假设我想将挂载点/home下的一部分空间分给挂载…