当前位置: 首页 > news >正文

零基础 “入坑” Java--- 十六、字符串String 异常

文章目录

  • 一、String
    • 1.字符串的不可变性
    • 2.字符串的修改
    • 3.StringBuilder和StringBuffer
    • 4.【字符串练习】
      • 4.1 字符串中的第一个唯一字符
      • 4.2 字符串最后一个单词的长度
      • 4.3 验证回文串
  • 二、异常
    • 1.初识异常
    • 2.异常的分类
    • 3.异常的处理
    • 4.异常处理流程总结
    • 5.自定义异常

在上一章节中,我们已经对String类型的 常用的方法进行了学习,String的知识不止于此。本章节,我们再来对String进行探究,并学习有关异常的知识。

一、String

1.字符串的不可变性

在之前对字符串的学习中,我们了解到 字符串是一种不可变对象,即字符串不能被修改。当我们对字符串进行操作时,都会生成一个新的字符串。

是什么原因导致字符串的不可变性的呢?我们来阅读一下String类型的源码:
在这里插入图片描述
字符串不能修改的真正原因是因为:value被private修饰,在类外拿不到value的引用,并非是因为final。

2.字符串的修改

    public static void main(String[] args) {String s = "hello";//避免直接对String类型的对象进行修改,因为String的不可变性,所有的修改都会创建新对象,效率低s += " world";System.out.println(s);}

使用上面这种方法,虽然可以完成对字符串的修改,但是效率很低。

我们可以使用StringBuilder和StringBuffer对字符串进行修改。

3.StringBuilder和StringBuffer

StringBuilder和StringBuffer的大部分功能都是相同的,我们就以StringBuilder举例:
在这里插入图片描述
在这里插入图片描述

    public static void main(String[] args) {//StringBuilder和StringBuffer功能类似StringBuilder stringBuilder = new StringBuilder();StringBuilder stringBuilder1 = new StringBuilder("666");//在原数据上进行修改,不会生成新的对象//String不可变,而StringBuilder和StringBuffer可变stringBuilder1.append(888);stringBuilder1.append("222");stringBuilder1.append(888).append(99.99);System.out.println(stringBuilder1);stringBuilder1.setCharAt(1, 'M');stringBuilder1.insert(1, "==");System.out.println(stringBuilder1);stringBuilder1.reverse();System.out.println(stringBuilder1);/*** String 和 StringBuilder并不能直接转换,要想转换:* 1.String 变 StringBuilder:利用StringBuilder构造方法 或 append方法*      构造方法:StringBuilder stringBuilder1 = new StringBuilder("666");* 2.StringBuilder 变 String:toString方法*/String str = stringBuilder1.toString();System.out.println(str);}

当我们需要频繁修改字符串的内容时,建议使用StringBuilder和StringBuffer。

在使用StringBuilder和StringBuffer时我们也需要注意:String和StringBuilder并不能直接转换。

有关字符串的知识我们已经了解的差不多了,接下来我们通过几道习题尝试运用一下学过的知识。

4.【字符串练习】

4.1 字符串中的第一个唯一字符

字符串中的第一个唯一字符

在这里插入图片描述
解题思路:
在这里插入图片描述
在这道题目中,有两个点值得我们注意:

1.因为字符’a’对应的ASCII码值为97,在申请数组时,为了节省空间,我们只申请26个,后续遍历数组时,用字符对应的ASCII码值 - ‘a’ 即可。
2.在第二次遍历数组时,需要对字符串进行遍历,寻找第一个只出现一次的字符,而不应对计数数组遍历。

class Solution {public int firstUniqChar(String s) {//定义一个计数数组,下标分别对应 26个英文字母 - 'a'int[] array = new int[26];//遍历字符串,将出现的字符在计数数组中对应的位置+1for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);array[ch - 'a']++;}//再次遍历字符串,寻找字符在计数数组中是否为1//注意:遍历字符串,不是遍历计数数组!!!for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if (array[ch - 'a'] == 1) {return i;}}return -1;}
}

4.2 字符串最后一个单词的长度

字符串最后一个单词的长度

在这里插入图片描述

import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNext()) { // 注意 while 处理多个 caseString s = in.nextLine();String[] str = s.split(" ");String ss = str[str.length - 1];System.out.println(ss.length());}}
}

在这道题目中,我们使用了split方法对字符串进行分割,获取最后一个单词,计算最后一个单词的长度即可。

4.3 验证回文串

验证回文串

在这里插入图片描述
解题思路:
在这里插入图片描述

class Solution {//判断是否为合法字符public boolean isLegal(char ch) {if (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z') {return true;}return false;}public boolean isPalindrome(String s) {//将所有大写字符转换为小写字符s = s.toLowerCase();int left = 0;int right = s.length() - 1;//left < right:相遇结束循环while (left < right) {//left < right:防止越界while (left < right && !isLegal(s.charAt(left))) {left++;}while (left < right && !isLegal(s.charAt(right))) {right--;}//至此,left 和 right均为合法字符if (s.charAt(left) != s.charAt(right)) {return false;} else {left++;right--;}}//循环条件不满足,结束循环,是回文串return true;}
}

在这道题目中,我们需要注意:最外层的while循环的"left < right"判断的是结束条件,而内层的while循环的"left < right"是判断是否越界(如:字符串中的字符 均为 非字母数字字符的情况)。

二、异常

1.初识异常

在Java中,将程序执行过程中发生的不正常的行为称为异常。 在之前的学习中,我们也已经遇到过很多可能会出现异常的情况:

  • 算术异常:
    在这里插入图片描述
  • 数组越界异常
    在这里插入图片描述
  • 空指针异常
    在这里插入图片描述

2.异常的分类

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

  • 编译时异常:在程序编译期间发生的异常,称为编译时异常,也称为受查异常。
  • 运行时异常:在程序执行期间发生的异常,称为运行时异常,也称为非受查异常。RuntimeException及其子类对应的异常,均称为运行时异常。

3.异常的处理

在Java中,对异常进行处理依赖于5个关键字:throw,try,catch,finally,throws。

  • try-catch捕获异常

使用 try-catch 进行防御性编程:

    public static void main(String[] args) {try {//System.out.println(10 / 0);int[] array1 = new int[]{1,2,3};//System.out.println(array1[6]);int[] array = null;System.out.println(array.length);} catch (ArithmeticException e) {System.out.println("捕获算术异常");} catch (ArrayIndexOutOfBoundsException e) {System.out.println("数组越界异常");} catch (NullPointerException e) {System.out.println("空指针异常");}}

将可能会出现异常的代码放在try的代码块中,使用catch匹配异常,当try中的代码出现异常时,就会寻找catch的匹配条件,如果满足,就会进入到对应的catch语句中。

try-catch 还可以与 finally 一起使用:

    public static void main(String[] args) {try {System.out.println(10 / 0);} catch (ArithmeticException e) { //catch需捕获到对应的异常,否则程序依旧异常终止e.printStackTrace(); //打印异常信息System.out.println("捕获异常");return;} finally {//finally中的代码一定会被执行,哪怕之前的代码中存在returnSystem.out.println("finally一定被执行");//不建议在finally中使用return语句}System.out.println("666");}

在使用 try - catch - finally 对异常进行捕获时,我们需要注意:

1.try代码块中,对于抛出异常位置之后的代码均不会执行。
2.如果抛出的异常的类型与catch的异常类型不匹配,则不会捕捉到异常,程序就会报错。
3.使用try-catch语句成功捕捉到异常之后,try-catch后的代码可以正常执行。
4.finally中的代码一定会被执行,哪怕之前的代码中存在return;不建议在finally中使用return语句,如果finally中和 try或catch 中均存在return语句,则执行finally中的return语句。
5.可以使用"printStackTrace"打印异常信息。

当多个异常的处理方式相同时,可以合并写为:

    public static void main(String[] args) {try {//System.out.println(10 / 0);int[] array1 = new int[]{1,2,3};System.out.println(array1[6]);int[] array = null;System.out.println(array.length);} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {System.out.println("捕获异常");} catch (NullPointerException e) {System.out.println("空指针异常");}}

Exception是所有异常的父类,当异常的处理具有父子关系时,一定是子类异常在前,父类异常在后,否则会报错:

    public static void main(String[] args) {try {//System.out.println(10 / 0);int[] array1 = new int[]{1,2,3};System.out.println(array1[6]);int[] array = null;System.out.println(array.length);} catch (NullPointerException e) {System.out.println("空指针异常");} catch (Exception e) {System.out.println("异常");}}

也可以通过Exception捕获所有异常,但并不推荐,捕获到的异常太模糊。


  • throw抛出异常
    在Java中,可以借助throw关键字,抛出一个指定的异常对象:
    //通过throws抛出异常,交给调用者处理(JVM)public static void main1(String[] args) throws CloneNotSupportedException {int a = 10;if (a == 10) {//throw 常用于抛出自定义异常throw new CloneNotSupportedException("a == 10"); //编译时异常}}

注意事项:

throw:
1.throw必须写在方法体内部。
2.通过throw抛出的对象必须是Exception或Exception的子类。
3.如果抛出的对象是RuntimeException或RuntimeException的子类,则可以不用自己处理,交给JVM处理。
4.如果抛出的是编译时异常,则必须用户自己处理,否则编译不通过。
5.异常一旦抛出,其后的代码均不会执行。


throws:
1.throws用于处理编译时异常,当用户不想处理方法中的编译时异常时,就可以通过throws将异常抛给方法的调用者处理。即当前方法不处理异常,提醒方法的调用者处理异常。
2.throws必须跟在方法的参数列表之后。
3.声明的异常必须是Exception或Exception的子类。
4.如果方法内部抛出了多个异常,throws之后必须跟多个异常类型,多个异常类型之间用","隔开;如果抛出的多个异常类型之间具有父子关系,也可以直接声明父类。
5.当调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出。


throw 和 throws:
当通过throw抛出一个运行时异常时,无需进行处理;但如果抛出的是一个编译时异常,就需要对其进行处理,最简单的方式就是通过throws处理。

4.异常处理流程总结

在这里插入图片描述

5.自定义异常

在我们进行自定义异常之前,我们先来看看异常的源码是怎样的(以算术异常为例):
在这里插入图片描述
自定义异常实现方式:

1.自定义一个类,并让其继承Exception或者RuntimeException,成为异常类。
2.实现一个带有String参数类型的构造方法,参数为出现异常的原因。

我们仿照源码编写自定义异常:

//运行时异常(非受查异常):extends RuntimeException
public class myException extends RuntimeException{public myException() {}public myException(String message) {super(message);}
}

此时我们就编写好了一个自定义的运行时异常。

使用也很简单:

    //运行时异常不用throwspublic static void main(String[] args) {int a = 10;if (a == 10) {throw new myException("我的异常");}}

我们再来编写一个自定义的编译时异常:

//编译时异常(受查异常):extends Exception
public class my_Exception extends Exception{public my_Exception() {}public my_Exception(String message) {super(message);}
}

使用编译时异常:

    //编译时异常必须throwspublic static void main1(String[] args) throws my_Exception {int a = 10;if (a == 10) {throw new my_Exception("我的异常");}}

由上面两个自定义异常的例子我们可以得出:

1.自定义异常通常继承Exception或者RuntimeException。
2.继承Exception的异常类默认是受查异常。
3.继承RuntimeException的异常类默认是非受查异常。


Ending。

http://www.dtcms.com/a/311538.html

相关文章:

  • 深入理解C++中的Lazy Evaluation:延迟计算的艺术
  • 搜索与图论(最小生成树 二分图)
  • 无人机光伏巡检漏检率↓78%!陌讯多模态融合算法实战解析
  • 关于解决wandb无法连接的问题(timed out problem)
  • spring学习笔记三
  • pyqt5显示任务栏菜单并隐藏主窗口,环境pyqt5+vscode
  • Python序列去重高级指南:保持顺序的高效去重技术
  • python:如何调节机器学习算法的鲁棒性,以支持向量机SVM为例,让伙伴们看的更明白
  • Linux 系统管理-15-OpenSSH 服务管理
  • NLP——Transformer
  • flutter实时播报的桌面应用遇到的问题
  • I2C(韦东山HAL库)
  • 2023年ASOC SCI2区TOP,可修灰狼优化算法RGWO+燃料电池参数辨识,深度解析+性能实测
  • 【无标题】根据11维拓扑量子色动力学模型(11D-TQCD)与当代宇宙学理论的融合分析,宇宙轮回的终结机制及其最终状态可系统论述如下:
  • 商品中台数据库设计
  • WPFC#超市管理系统(4)入库管理
  • 音视频学习(四十八):PCM和WAV
  • 基于深度学习的医学图像分析:使用GAN实现医学图像增强
  • 进阶向:Python生成艺术图案(分形、数学曲线)
  • MySQL索引解析
  • vue3pinia
  • Corrosion2靶机
  • Cyber Weekly #63
  • 搜索引擎评估革命:用户行为模型如何颠覆传统指标?
  • Sklearn 机器学习 数据聚类 用Numpy自己实现聚类
  • 【C++】类和对象(2)
  • 使用keil点亮stc8核心板的灯
  • 逻辑回归 银行贷款资格判断案列优化 交叉验证,调整阈值,下采样与过采样方法
  • MQTT 入门教程:MQTT工具调式
  • 堆----2.前 K 个高频元素