Java基础2:Java异常+并发(搬砖整理,侵权删文)

本文详细介绍了Java中的异常处理,包括异常架构、关键字、处理方式和面试常见问题。同时,深入讲解了并发编程的基础知识,如线程、进程、同步、线程池以及并发工具类的使用,如CountDownLatch、Semaphore等。文章还讨论了String对象的特点和在HashMap中的应用,以及包装类的自动装箱拆箱机制。
摘要由CSDN通过智能技术生成

Java基础2:Java异常+并发(搬砖整理,侵权删文)

七、常用API

1、Spring相关

1、字符型常量和字符串常量的区别

​ 1、形式上:字符型常量是单引号引起一个字符,字符串常量是双引号引起的若干个字符

​ 2、含以上:字符型常量相当于一个整型值(ASCⅡ值),可以参加表达式运算;字符串常量代表一个地址值(该字符串在内存中的存放位置)

​ 3、占内存大小:字符常量只占一个字节;字符串常量占若干个字节(至少一个字符结束标志)

2、字符串常量池

​ 字符串常量池位于堆中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时JVM会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不在,则实例化一个字符串放到池中,并返回其引用。

3、String的特性

1、不变性:String是只读字符串,是一个典型的immutable对象,对他进行任何操作,其实都是创建一个新对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据得一致性。(这里说的不可变是指原来的String内若不变,但是引用是可以变化的。通过反射也可以改变所谓的”不可变对象“:用反射可以访问私有成员,然后反射出String对象中的value属性,进而通过获得的value引用改变数组的结构。)

String str = "Hello";
str = str + " World";
System.out.println("str=" + str);

str=Hello World
// 创建字符串"Hello World", 并赋给引用s
String s = "Hello World";

System.out.println("s = " + s); // Hello World

// 获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");

// 改变value属性的访问权限
valueFieldOfString.setAccessible(true);

// 获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);

// 改变value所引用的数组中的第5个字符
value[5] = '_';

System.out.println("s = " + s); // Hello_World
s = Hello World
s = Hello_World

2、常量池优化:String对象创建之后,会在字符串常量池中囧型缓存,如果下次创建同样的对象时,会直接返回缓存的引用。

3、final:使用final来定义String类,表示String类不能被继承,提高了系统的安全性。

4、String str="i"与 String str=new String(“i”)一样吗?

​ 不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

​ String s = new String(“xyz”);创建了两个对象,一个在字符串常量池”xyz“,另一个是new创建在堆区上的对象。

5、字符串反转

​ 使用StringBuilder或者StringBuffer的reverse()方法。

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba

6、String常用的方法

indexOf()返回指定字符的索引

charAt()返回指定索引处的字符

replace()字符串替换

trim()去除字符串两端的空白

split()分割字符串,返回一个分割后的字符串数组

getBytes()返回字符串debyte类型数组

length()返回字符串长度

toLowerCase()将字符串转换为小写字母

toUpperCase()将字符串转换为大写字母

substring()截取支付穿

equals()字符串比较

7、在使用HashMap的时候,用String做key有什么好处?

​ HashMap内部实现是通过key的hashcode来确定value的存储位置,因为字符串是不可变的,所以当创建字符串时,它的hashcode被缓存下来,不需要再次计算,所以相比于其他对象更快。

8、String和StringBuffer、StringBuilder的区别

1、可变性

​ String类中使用字符数组保存字符串,private final char value[],所以String对象是不可变的。StringBuffer和StringBuilder都继承自AbstractStringBuilder类,在这个类中也是使用字符数组保存字符串char[] value,这两种对象都是可变的。

2、线程安全性

​ String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuffer与StringBuilder的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

3、性能

​ 每次对S听类型进行该拜年的时候,都会生成一个性的String对象,然后将指针指向新的String对象。StringBuffer与StringBuilder每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StringBuilder每次都会比使用StringBuffer获得10%-15%左右的性能提升,但却有多线程不安全的风险

4、总结

​ 操作少量数据用String,单线程操作字符串缓冲区下操作大量数据用StringBuilder,多线程操作字符串缓冲区下操作大量数据用StringBuffer。

2、Data相关

3、包装类相关

1、自动装箱和拆箱

​ 装箱:将基本类型用它们对应的引用类型包装起来

​ 拆箱:将包装类型转换为基本数据类型

2、int和integer的区别

​ Java是一个几乎纯面向对象的语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当作对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类型就是integer,从Java5开始引入自动装箱和拆箱机制,使得二者可以相互转换。

​ Java为每一个原始类型提供包装类型:

​ 原始类型:boolean,char,byte,short,int,long,float,double.

​ 包装类型:Boolean,Character,Byte,Short,Integer,Float,Double.

3、Integer a = 127与Integer b = 127相等吗

​ 对于对象引用类型:==比较的是对象的内存地址,对于基本数据类型:==比较的是值。

​ 如果整型字面量在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,故a==b;超过范围则返回false。

public static void main(String[] args) {
   
    Integer a = new Integer(3);
    Integer b = 3;  // 将3自动装箱成Integer类型
    int c = 3;
    System.out.println(a == b); // false 两个引用没有引用同一对象
    System.out.println(a == c); // true a自动拆箱成int类型再和c比较
    System.out.println(b == c); // true

    Integer a1 = 128;
    Integer b1 = 128;
    System.out.println(a1 == b1); // false

    Integer a2 = 127;
    Integer b2 = 127;
    System.out.println(a2 == b2); // true
}

八、Java异常

https://thinkwon.blog.csdn.net/article/details/104390689

1、异常架构与异常关键字

1、Java异常简介

​ Java异常是Java提供的一种识别及响应错误的一致性机制。Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序的健壮性。在有效使用异常的情况下异常能清晰的回答what, where, why这3个问题:异常类型回答了“什么”被抛出,异常堆栈跟踪回答了“在哪”抛出,异常信息回答了“为什么”会抛出。

2、Java异常架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2zKdNOPg-1626232307526)(C:\Users\四叔\AppData\Roaming\Typora\typora-user-images\image-20210703215123633.png)]

1、Throwable

​ Throwable 是 Java 语言中所有错误与异常的超类。Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情况。Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取堆栈跟踪数据等信息。

2、ERROR

定义:Error 类及其子类。程序中无法处理的错误,表示运行应用程序中出现了严重的错误。

特点:此类错误一般表示代码运行时 JVM 出现问题。通常有 Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如 OutOfMemoryError:内存不足错误;StackOverflowError:栈溢出错误。此类错误发生时,JVM 将终止线程。

这些错误是不受检异常,非代码性错误。因此,当此类错误发生时,应用程序不应该去处理此类错误。按照Java惯例,我们是不应该实现任何新的Error子类的!

3、Exception

​ 程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类:运行时异常和编译时异常.

运行时异常
定义:RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。

特点:Java 编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。比如NullPointerException空指针异常、ArrayIndexOutBoundException数组下标越界异常、ClassCastException类型转换异常、ArithmeticExecption算术异常。此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。虽然 Java 编译器不会检查运行时异常,但是我们也可以通过 throws 进行声明抛出,也可以通过 try-catch 对它进行捕获处理。如果产生运行时异常,则需要通过修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!

RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。

编译时异常
定义: Exception 中除 RuntimeException 及其子类之外的异常。

特点: Java 编译器会检查它。如果程序中出现此类异常,比如 ClassNotFoundException(没有找到指定的类异常),IOException(IO流异常),要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。

4、受检异常与非受检异常

​ Java 的所有异常可以分为受检异常(checked exception)和非受检异常(unchecked exception)。

受检异常
编译器要求必须处理的异常。正确的程序在运行过程中,经常容易出现的、符合预期的异常情况。一旦发生此类异常,就必须采用某种方式进行处理。除 RuntimeException 及其子类外,其他的 Exception 异常都属于受检异常。编译器会检查此类异常,也就是说当编译器检查到应用中的某处可能会此类异常时,将会提示你处理本异常——要么使用try-catch捕获,要么使用方法签名中用 throws 关键字抛出,否则编译不通过。

非受检异常
编译器不会进行检查并且不要求必须处理的异常,也就说当程序中出现此类异常时,即使我们没有try-catch捕获它,也没有使用throws抛出该异常,编译也会正常通过。该类异常包括运行时异常(RuntimeException极其子类)和错误(Error)。

3、Java异常关键字

• try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
• catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
• finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
• throw – 用于抛出异常。
• throws – 用在方法签名中,用于声明该方法可能抛出的异常。

2、Java异常处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uiuNrlfX-1626232307539)(C:\Users\四叔\AppData\Roaming\Typora\typora-user-images\image-20210703220033503.png)]

​ Java通过面向对象的方法进行异常处理,一旦方法抛出异常,系统自动根据该异常对象寻找合适异常的处理器来处理该异常,把各类不同的异常进行分类,并提供良好的接口。在Java中,每一个异常都是一个对象,他是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java的异常处理是通过5个关键字来实现的:try catch throw throws finally。在Java中异常的处理机制分为声明异常和捕获异常。

1、声明异常

​ 通常,应该捕获那些知道如何处理的异常,降不知道如何处理的异常继续传递下去。传递一场可以再方法签名处使用throws关键字生命可能会抛出的异常。

​ 注意:非检查异常(Error、RuntimeException或他们的子类)不可使用throws关键字来生命要跑出的异常;一个方法出现编译时异常,就需要try-catch/throws处理,否则会导致编译错误。

2、抛出异常

​ 如果你觉得解决不了某些异常问题,且不需要调用者处理,就可以抛出异常。throw关键字的作用是在方法内部抛出一个Throwable类型的异常。任何Java代码都可以通过throw语句抛出异常。

3、捕获异常

​ 程序通常在运行之前不会报错,但是运行后可能会出现某些未知的错误,但是还不想直接抛出到上级,那么就要通过try-catch的形式进行异常捕获,之后根据不同的异常情况来进行相应的处理。

4、如何选择异常类型

在这里插入图片描述

5、常见异常处理方式

1、直接抛出异常

​ 通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以再方法签名处使用throws关键字声明可能会抛出的异常。

private static void readFile(String filePath) throws IOException {
   
    File file = new File(filePath);
    String result;
    BufferedReader reader = new BufferedReader(new FileReader(file));
    while((result = reader.readLine())!=null) {
   
        System.out.println(result);
    }
    reader.close();

2、封装异常再抛出

​ 有时候我们会从catch中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需要暴露太多的内部异常细节。

private static void readFile(String filePath) throws MyException {
       
    try {
   
        // code
    } catch (IOException e) {
   
        MyException ex = new MyException("read file failed.");
        ex.initCause(e);
        throw ex;
    }
}
3、捕获异常

​ 在一个try-catch语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理,用catch也可以捕获多种类型异常,用|隔开。

private static void readFile(String filePath) {
   
    try {
   
        // code
    } catch (FileNotFoundException e) {
   
        // handle FileNotFoundException
    } catch (IOException e){
   
        // handle IOException
    }
}
private static void readFile(String filePath) {
   
    try {
   
        // code
    } catch (FileNotFoundException | UnknownHostException e) {
   
        // handle FileNotFoundException or UnknownHostException
    } catch (IOException e){
   
        // handle IOException
    }
}
4、自定义异常

​ 习惯上,定义一个异常类应包含两个构造函数,一个无参构造和一个带有详细构造信息的构造函数(Throwable的toString方法会打印这些详细信息,调试的时候很有用)。

public class MyException extends Exception {
   
    public MyException(){
    }
    public MyException(String msg){
   
        super(msg);
    }
    // ...
}
5、try-catch-finally

​ 当方法发生异常,异常处之后的代码不会再执行,如果之前获取一些本地资源需要释放,则需要在方法正常结束时和catch语句中都调用释放本地资源的代码,显得代码比较繁琐,finally语句可以解决这个问题。

private static void readFile(String filePath) throws MyException {
   
    File file = new File(filePath);
    String result;
    BufferedReader reader = null;
    try {
   
        reader = new BufferedReader(new FileReader(file));
        while((result = reader.readLine())!=null) {
   
            System.out.println(result);
        }
    } catch (IOException e) {
   
        System.out.println("readFile method catch block.");
        MyException ex = new MyException("read file failed.");
        ex.initCau
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值