1.API
1.1 API概述-帮助文档的使用
-
什么是API
API (Application Programming Interface) :应用程序编程接口
-
java中的API
指的就是 JDK 中提供了各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。
如何使用API帮助文档 :
-
打开帮助文档
-
找到索引选项卡中的输入框
-
在输入框中输入Random
-
看类在哪个包下
-
看类的描述
-
看构造方法
-
看成员方法
1.2 键盘录入字符串
java.util.Scanner类 :
nextXxx()方法:当扫描器扫描到空格,回车,tab时,会过滤掉它们并放入到扫描器的缓存中,如果下一次扫描器继续扫描时,就会将数据取出给下一个nextXxx方法。
通过 Scanner 类的 next() 与 nextLine() 方法获取输入的字符串:
nextLine() : 只以 回车 作为结束输入的标记
next() : 结束标记: 以空格, 回车,tab键作为结束标记
next() 与 nextLine() 区别:
next():
-
只有输入有效字符之后,next()方法才将其后面输入的空格键、Tab键或Enter键等视为分隔符或结束符。
-
在输入有效字符之前遇到的空格键、Tab键或Enter键结束符,会自动去掉。
-
一定要读取到有效字符,才会结束输入
-
next() 不能得到带有空格的字符串。
nextLine():
-
1、只以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
-
2、可以获得空格。
代码实现 :
使用nextLine方法:
package com.wedu.api;
import java.util.Scanner;
public class Demo1Scanner {
public static void main(String[] args) {
// 1. 创建Scanner对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
// 2. 调用nextLine方法接收字符串
// ctrl + alt + v : 快速生成方法的返回值
String s = sc.nextLine();
System.out.println(s);
}
}
使用nextLine()的问题:nextInt和nextLine方法配合使用的时候,会导致nextLine方法没有键盘录入的机会:
package com.wedu.api;
import java.util.Scanner;
public class Demo2Scanner {
/*
建议: 今后键盘录入数据的时候, 如果是字符串和整数一起接受, 建议使用next方法接受字符串.
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入整数:");
int num = sc.nextInt(); // 10 + 回车换行
System.out.println("请输入字符串:");
String s = sc.nextLine();
System.out.println(num);
System.out.println(s);
}
}
package demo;
import java.util.Scanner;
public class Demo2Scanner {
/*
建议: 今后键盘录入数据的时候, 如果是字符串和整数一起接受, 建议使用next方法接受字符串.
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入整数:");
int num = sc.nextInt(); // 10 + 回车换行
System.out.println("请输入字符串:");
String s = sc.next();
System.out.println(num);
System.out.println(s);
}
}
2. String类
引言:java中定义了3个封装字符串的类,它们三个都位于java.lang包中,并提供了一系列操作字符串的方法。
-
String类定义的字符串对象一旦创建就不可修改,修改时会产生新的实例对象,而StringBuffer类和StringBuilder类的内容和长度都是可以修改的,不会产生新的对象;StringBuffer类是线程安全的,StringBuilder类是非线程安全的,但更高效
2.1 String概述
1. String 类在 java.lang 包下(使用在java.lang包下的类,不需要导包)
2. String类的对象一旦创建其内容就不可修改,修改会产生新的String实例对象;变的只是栈内存中引用对象的值
3. String 类代表字符串,Java 程序中,所有用双引号括起来的字符串(例如“abc”)都是String类的实例
2.2 String类的构造方法
使用String类的构造方法实例化String对象
常用的构造方法
使用String类的构造方法:
package com.wedu.string;
public class Demo2StringConstructor {
public static void main(String[] args) {
//使用String类的无参构造方法创建字符串对象
String s1 = new String();
System.out.println(s1);
// public String(char[] chs) : 根据字符数组的内容,来创建字符串对象
char[] chs = {'a','b','c'};
String s2 = new String(chs);
System.out.println(s2);
// public String(String original) : 根据传入的字符串常量,来创建字符串对象
String s3 = new String("123");
System.out.println(s3);
}
}
字符串的特点
-
java程序中,所有的双引号字符串(例如:"123"),都是String类型的对象
-
虽然String实例的值不可变,但是它们可以共享
注意:
-
总结:java程序中,所有的字符串常量都是字符串对象,并且存储在方法区的字符串常量池中
-
虽然String实例的值都不可变,但是它们可以共享
2.4 不同方式创建字符串对象的区别
-
通过构造方法(new)创建字符串对象
每次 通过new创建的字符串对象 时 ,都会在堆空间中为其分配一个新的内存空间,虽然内容相同,但是地址值不同
-
字符串字面量直接赋值的方式创建字符串对象
系统首先会检查该字符串是否存在于字符串常量池(方法区中):
-
如果不存在,会在字符串常量池中创建一个新的字符串对象
-
如果存在,不会创建新的String实例而是直接引用(String实例共享的原因)
-
2.5 字符串的比较
通过==运算符来比较:
-
用于比较基本数据类型时:比较的是具体的值
-
用于比较引用数据类型时:比较的是对象的地址值
通过String类的方法 :
-
public boolean equals(String s) :比较两个字符串的内容是否相同、区分大小写
-
equalsIgnoreCase(String s):比较两个字符串的内容是否相同,忽略大小写,
-
注意
-
1、equals()方法对于StringBuffer类,StringBuilder类不起作用,因为只有String类重写了Object类的equals方法,改为判断两个对象的内容
-
代码 :
package com.wedu.stringmethod;
public class Demo1Equals {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "ABC";
String s3 = "abc";
// equals : 比较字符串内容, 区分大小写
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
// equalsIgnoreCase : 比较字符串内容, 忽略大小写
System.out.println(s1.equalsIgnoreCase(s2));
}
}
字符串中常见的面试题
①打印字符串对象名的时候,打印的是字符串的内容,而不是字符串对象的地址呢?
-
打印字符串对象时,会自动调用对象的toString方法,toString方法会打印字符串的内容
-
不论是哪种引用数据类型,直接打印对象名,都会自动调用toString方法.
-
如果此类没有重写Object类中的toString方法,那么就调用Object类的toString方法,即打印出来的是地址(全类名+@+16进制的hashCode).
-
如果此类重写了toString方法,那么就调用重写的toString方法.
-
②以下str1==str3为什么结果是false?
③为什么以下代码结果是true?
答:java中存在常量优化机制,在编译时就会将"a"+"b"+"c"拼接为"abc"
java中的常量优化机制:给一个变量赋值时,如果“=”号右边是常量的表达式没有一个变量,那么就会在编译阶段就计算该常量表达式的结果。
-
编译时常量折叠(Compile-time Constant Folding):在编译阶段,编译器会对常量表达式进行求值,并将结果直接替换到代码中。 例如,对于表达式int result = 10 * 5;编译器会在编译阶段将其优化为int result = 50;,避免了在每次运行时都进行乘法运算。
-
字符串常量拼接优化(String Concatenation Optimization):对于字符串常量的拼接操作,编译器会尽可能地在编译阶段进行优化,减少运行时的开销。例如,对于字符串常量的拼接操作String result = "Hello" + "World";,编译器会在编译阶段将其优化为String result = "HelloWorld";,避免了在运行时使用StringBuilder(或StringBuffer)类进行拼接操作。
-
注:常量优化机制顾名思义,只能有常量参与表达式,不能有变量参与
2.6 用户登录案例
使用到的方法:字符串的内容比较,用equals() 方法实现
案例需求 :
已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
实现步骤 :
-
已知用户名和密码,定义两个字符串表示即可
-
键盘录入要登录的用户名和密码,用 Scanner 实现
-
拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
-
字符串的内容比较,用equals() 方法实现
-
用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循
代码实现 :
package com.wedu.test;
import java.util.Scanner;
public class Test1 {
/*
需求:已知用户名和密码,请用程序实现模拟用户登录。
总共给三次机会,登录之后,给出相应的提示
思路:
1. 已知用户名和密码,定义两个字符串表示即可
2. 键盘录入要登录的用户名和密码,用 Scanner 实现
3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
字符串的内容比较,用equals() 方法实现
4. 用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环
*/
public static void main(String[] args) {
// 1. 已知用户名和密码,定义两个字符串表示即可
String username = "admin";
String password = "123456";
// 2. 键盘录入要登录的用户名和密码,用 Scanner 实现
Scanner sc = new Scanner(System.in);
// 4. 用循环实现多次机会,这里的次数明确,采用for循环实现
for(int i = 1; i <= 3; i++){
System.out.println("请输入用户名:");
String scUsername = sc.nextLine();
System.out.println("请输入密码:");
String scPassword = sc.nextLine();
// 3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
if(username.equals(scUsername) && password.equals(scPassword)){
System.out.println("登录成功");
break;
}else{
if(i == 3){
System.out.println("您的登录次数已达到今日上限, 请明天再来");
}else{
System.out.println("登录失败,您还剩余" + (3-i) +"次机会");
}
}
}
}
}
2.7 遍历字符串案例
使用到的方法:
-
public char charAt(int index):返回指定索引处的字符,字符串的索引也是从0开始的
-
字符串的索引从0开始,到字符串长度-1结束,没有c语言里面的'/0'为结束符
-
-
public int length():返回此字符串的长度
案例需求 :
键盘录入一个字符串,使用程序实现在控制台遍历该字符串的每个字符
实现步骤 :
-
键盘录入一个字符串,用 Scanner 实现
-
遍历字符串,首先要能够获取到字符串中的每一个字符, public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的
-
遍历字符串,其次要能够获取到字符串的长度, public int length():返回此字符串的长度
-
遍历打印
代码实现 :
package com.wedu.test;
import java.util.Scanner;
public class Test2 {
/*
需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串
思路:
1. 键盘录入一个字符串,用 Scanner 实现
2. 遍历字符串,首先要能够获取到字符串中的每一个字符
3. 遍历字符串,其次要能够获取到字符串的长度
4. 遍历打印
9
*/
public static void main(String[] args) {
// 1. 键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String s = sc.nextLine();
// 2. 遍历字符串,获取字符串中的每一个字符
for(int i = 0; i < s.length(); i++){
// i : 字符串的每一个索引
char c = s.charAt(i);
System.out.println(c);
}
}
}
2.8 统计字符次数案例
使用到的方法:
-
public char[] toCharArray( ):将当前字符串拆分为字符数组并返回
案例需求 :
键盘录入一个字符串,统计该字符串中大写字母,小写字母,数字字符出现的次数(不考虑其他字符)
实现步骤 :
-
键盘录入一个字符串,用 Scanner 实现
-
将字符串拆分为字符数组
-
遍历字符数
代码实现 :
package string.demo;
import java.util.Scanner;
public class StringDemo3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入一个字符串:");
String str = sc.nextLine();
//定义三个变量,记录每一种类型出现的次数
int upperCaseCount = 0;
int lowerCaseCount = 0;
int numberCount = 0;
//将字符串拆分为字符数组
char[] chars = str.toCharArray();
//遍历字符数组,得到每一个字符
for (int i = 0;i<chars.length;i++){
char c = chars[i];
if(c >='A' && c <= 'Z'){
upperCaseCount++;
} else if (c >= 'a' && c <= 'z') {
lowerCaseCount++;
}else if (c >= '0' && c <= '9'){
numberCount++;
}
}
System.out.println("大写字母出现的次数:" + upperCaseCount);
System.out.println("小写字母出现的次数:" + lowerCaseCount);
System.out.println("数字出现的次数:" + numberCount);
}
}
2.9 手机号屏蔽-字符串截取
需要用到的方法:
-
public String substring(int beginIndex, int endIndex):截取此字符串beginIndex到endIndex索引范围的字符串,并返回
案例需求 :
以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽 最终效果为:1561234
实现步骤 :
-
键盘录入一个字符串,用 Scanner 实现
-
截取字符串前三位
-
截取字符串后四位
-
将截取后的两个字符串,中间加上进行拼接,输出结果
代码实现 :
package com.wedu.test;
import java.util.Scanner;
public class Test5 {
/*
需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:156****1234
思路:
1. 键盘录入一个字符串,用 Scanner 实现
2. 截取字符串前三位
3. 截取字符串后四位
4. 将截取后的两个字符串,中间加上****进行拼接,输出结果
*/
public static void main(String[] args) {
// 1. 键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String telString = sc.nextLine();
// 2. 截取字符串前三位
String start = telString.substring(0,3);
// 3. 截取字符串后四位
String end = telString.substring(7);
// 4. 将截取后的两个字符串,中间加上****进行拼接,输出结果
System.out.println(start + "****" + end);
}
}
2.10 敏感词替换-字符串替换
案例需求 :
键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换
实现步骤 :
-
键盘录入一个字符串,用 Scanner 实现
-
替换敏感词 String replace(CharSequence target, CharSequence replacement) 将当前字符串中的target内容,用replacement替换,并返回新的字符串
-
输出结果
代码实现 :
package com.wedu.test;
import java.util.Scanner;
public class Test6 {
public static void main(String[] args) {
// 1. 从键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String s = sc.nextLine();
// 2. 替换敏感词
String result = s.replace("TMD","***");
// 3. 输出结果
System.out.println(result);
}
}
2.11 切割字符串
使用到的方法:
String[] split(String regex) :根据传入的字符串规则,将字符串切割成字符串数组,并将字符串数组返回
案例需求 :
以字符串的形式从键盘录入学生信息,例如:“张三 , 23”
从该字符串中切割出有效数据,封装为Student学生对象
实现步骤 :
-
编写Student类,用于封装数据
-
键盘录入一个字符串,用 Scanner 实现
-
根据逗号切割字符串,得到(张三)(23)
-
从得到的字符串数组中取出元素内容
-
通过Student类的有参构造方法封装为对象
-
调用对象getXxx方法,取出数据并打印。
代码实现 :
package pojo;
public class Student {
private String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package string.demo;
import pojo.Student;
import java.util.Scanner;
public class StringDemo4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入学生信息");
String str = sc.nextLine();
//用逗号分隔字符串
String[] split = str.split(",");
//从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象
String name = split[0];
String ageStr = split[1];
//将字符串转换为int类型
int age = Integer.parseInt(ageStr);
Student student = new Student(name, age);
System.out.println(student);
}
}
2.12 String方法小结
String类中的常用方法 :
public boolean equals(Object anObject) 比较两个字符串的内容,严格区分大小写
public boolean equalsIgnoreCase(String anotherString) 比较两个字符串的内容,忽略大小写
public int length() 返回此字符串的长度
public char charAt(int index) 返回索引处的字符(索引从0开始)
public char[] toCharArray() 将字符串拆分成字符数组后返回
public String[] split(String regex) 根据传入的字符串规则切割字符串,得到字符串数组并返回
public String substring(int beginIndex, int endIndex) 截取开始和结束索引范围的字符串(包含头,不包含尾),得到新的字符串返回
public String substring(int beginIndex) 从传入的索引处开始截取 到末尾,得到新的字符串
public String replace(CharSequence target, CharSequence replacement) :在当前字符串中,将旧字符序列,用新字符序列替换,并返回新的字符串
3 StringBuilder类
3.1 StringBuilder类概述
概述 : StringBuilder对象的内容是可修改的,并且修改不会产生新的对象,线程不安全,但是高效。也在java.lang包下
3.2 StringBuilder类和String类的区别
-
String类:内容是不可变的
-
StringBuilder类:内容是可变的
3.3 StringBuilder类的构造方法
常用的构造方法
方法名 | 说明 |
---|---|
public StringBuilder() | 创建一个空的StringBuilder对象,不含任何内容 |
public StringBuilder(String str) | 根据字符串的内容,创建一个可变字符串对象 |
示例代码
public class StringBuilderDemo01 {
public static void main(String[] args) {
//public StringBuilder():创建一个空白可变字符串对象,不含有任何内容
StringBuilder sb = new StringBuilder();
System.out.println("sb:" + sb);
System.out.println("sb.length():" + sb.length());
//public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象
StringBuilder sb2 = new StringBuilder("hello");
System.out.println("sb2:" + sb2);
System.out.println("sb2.length():" + sb2.length());
}
}
3.4 StringBuilder常用的成员方法
-
添加和反转方法
方法名 说明 public StringBuilder append(任意类型) 追加数据,并返回对象本身 public StringBuilder reverse() 将StringBuilder对象里的字符串反转,并返回本对象 -
示例代码
public class StringBuilderDemo01 {
public static void main(String[] args) {
//创建对象
StringBuilder sb = new StringBuilder();
//链式调用
sb.append("hello").append("world").append("java").append(100);
System.out.println("sb:" + sb);
//public StringBuilder reverse():返回相反的字符序列
sb.reverse();
System.out.println("sb:" + sb);
}
}
3.5StringBuilder和String相互转换
都是使用StringBuilder类的方法
-
String转换为StringBuilder
public StringBuilder(String s)方法:通过StringBuilder类的构造方法可以把 String对象 转换为 StringBuilder
-
StringBuilder转换为String
public String toString()方法:通过StringBuilder类的 toString() 可以把 此StringBuilder对象 转换为 String
-
示例代码
package string.demo;
public class StringDemo4 {
public static void main(String[] args) {
//String转换为StringBuilder对象
String str = "hello";
StringBuilder sb = new StringBuilder(str);
System.out.println(sb);
sb.append(" world");
//StringBuilder对象转换为String对象
String result = sb.toString();
System.out.println(result);
}
}
3.6 StringBuilder拼接字符串案例
案例需求 :
定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
并在控制台输出结果。例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
实现步骤 :
-
定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
-
定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。 返回值类型 String,参数列表 int[] arr
-
在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
-
调用方法,用一个变量接收结果
-
输出结果
代码实现 :
/*
思路:
1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
返回值类型 String,参数列表 int[] arr
3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
4:调用方法,用一个变量接收结果
5:输出结果
*/
public class StringBuilderTest01 {
public static void main(String[] args) {
//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
int[] arr = {1, 2, 3};
//调用方法,用一个变量接收结果
String s = arrayToString(arr);
//输出结果
System.out.println("s:" + s);
}
//定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回
/*
两个明确:
返回值类型:String
参数:int[] arr
*/
public static String arrayToString(int[] arr) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i=0; i<arr.length; i++) {
if(i == arr.length-1) {
sb.append(arr[i]);
} else {
sb.append(arr[i]).append(", ");
}
}
sb.append("]");
String s = sb.toString();
return s;
}
}
4.异常
位于java.lang包下
4.1 异常
-
异常的概述
异常就是程序出现了不正常的情况
-
异常的体系结构:java提供了大量异常类,它们都继承自java.lang.Throwable类。
-
Error是错误类,错误不是异常,通过代码无法处理。
-
Exception是异常类,它表示程序本身可以处理的错误
-
RuntimeException类及其子类:表示运行时异常
-
除RuntimeException之外的所有异常类:表示编译时异常
-
-
4.2 编译时异常和运行时异常的区别
-
编译时异常
-
都是Exception类及其子类
-
编译时必须显示处理,否则程序无法通过编译
-
-
运行时异常
-
都是RuntimeException类及其子类
-
无需显示处理,也可以和编译时异常一样处理
-
-
图示
异常处理的过程
当程序出现异常时:
-
会在异常的位置生成一个异常类的对象
-
看程序是否有处理异常的代码 (java中处理异常的两种方式throws try-catch)
-
如果有,按照处理异常的逻辑处理
-
如果没有,交给方法的调用者处理
-
-
方法调用会依次传给main方法,如果main方法依旧没有处理异常,就会给JVM来处理
4.3 JVM默认处理异常的方式
-
如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理。
-
JVM默认处理异常的方式有如下两个步骤:
-
①把异常的名称,错误原因及异常出现的位置等信息输出在控制台
-
②让程序停止执行
-
4.4 查看异常信息
控制台在打印异常信息时,会打印异常类名,异常出现的原因,异常出现的位置
我们调bug时,可以根据提示,找到异常出现的位置,分析原因,修改异常代码
4.5 throws方式处理异常
-
定义格式:在方法的括号后面写 throws 异常类型
-
作用:使用throws关键字,声明方法可能会抛出(发生)的异常类型。
public void 方法() throws 异常类名 {
}
- 示例代码
public class ExceptionDemo {
public static void main(String[] args) throws ParseException{
System.out.println("开始");
// method();
method2();
System.out.println("结束");
}
//编译时异常
public static void method2() throws ParseException {
String s = "2048-08-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
}
//运行时异常
public static void method() throws ArrayIndexOutOfBoundsException {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
}
-
注意事项
-
编译时异常必须要进行异常处理,有两种处理方案:try...catch …或者 throws,如果采用 throws 这种方案,在方法上进行显示声明,将来谁调用这个方法谁处理
-
运行时异常因为在运行时才会发生,所以在方法后面可以不写throws,运行时出现异常默认交给jvm处理
-
定义方法时使用了throws关键字抛出异常,将来在调用该方法时必须用try...catch处理,否则就会编译错误。
-
4.6 throw手动抛出异常
以前出现的异常,都是虚拟机自动创建异常对象,然后抛给调用者。现在,我们可以通过throw关键字手动抛出一个异常实例
-
格式
throw new 异常类("告知信息");
-
注意
这个格式是在方法内的,手动抛出异常之后的代码不会执行
-
throws关键字和throw关键字的区别
throws throw 用在方法声明后面,跟的是异常类名 用在方法体内,跟的是异常对象名 表示声明异常,调用该方法有可能会出现这样的异常 表示手动抛出异常对象,由方法体内的语句处理 -
示例代码
public class ExceptionDemo8 {
public static void main(String[] args) {
//int [] arr = {1,2,3,4,5};
int [] arr = null;
printArr(arr);//就会 接收到一个异常.
//我们还需要自己处理一下异常.
}
private static void printArr(int[] arr) {
if(arr == null){
//调用者知道成功打印了吗?
//System.out.println("参数不能为null");
throw new NullPointerException(); //当参数为null的时候
//手动创建了一个异常对象,抛给了调用者,产生了一个异常
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
4.7 try-catch方式处理异常
-
定义格式
try {
可能出现异常的代码;
} catch(异常类名 变量名) { //小括号里面声明catch所能接收的异常类型:(Exception类及其子类 e)
处理异常的代码;
}
-
执行流程
-
程序从 try 里面的代码开始执行
-
出现异常时,会在异常的位置生成一个(对应的)异常类对象,并将这个异常对象传递给catch代码块,跳转到对应的 catch 中去处理异常
-
执行完毕之后,程序还会继续执行try-catch后面的代码
-
-
示例代码
public class ExceptionDemo01 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你访问的数组索引不存在,请回去修改为正确的索引");
}
}
}
-
try-catch处理异常的注意事项
-
如果 try 中没有遇到问题,怎么执行?
会把try中所有的代码全部执行完,但不会执行catch里面的代码
-
如果 try 中遇到了问题,那么 try 下面的代码还会执行吗?
try中 异常语句 下面的代码就不会再执行了,直接跳转到对应的catch语句中。 当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码
-
如果出现的问题没有被捕获(也就是catch后声明的异常类型和try中发送的异常不匹配),那么程序如何运行?
那么try...catch就相当于没有写. 默认交给虚拟机处理.
-
同时可能出现多个异常怎么处理?
出现多个异常,那么就写多个catch就可以了. 注意点:如果多个异常之间存在继承关系.那么父类一定要写在下面,因为catch代码块是按顺序捕获的
-
4.8 Throwable成员方法
-
常用方法
方法名 说明 public String getMessage() 返回此 throwable 的详细消息字符串 public String toString() 返回此可抛出的简短描述 public void printStackTrace() 把异常的错误信息输出在控制台 -
示例代码
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
// e.printStackTrace();
//public String getMessage():返回此 throwable 的详细消息字符串
// System.out.println(e.getMessage());
//Index 3 out of bounds for length 3
//public String toString():返回此可抛出的简短描述
// System.out.println(e.toString());
//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//public void printStackTrace():把异常的错误信息输出在控制台
e.printStackTrace();
// java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at com.wedu_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
// at com.wedu_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
}
}
}
4.9 异常的练习
-
需求
键盘录入学生的姓名和年龄,其中年龄为18 - 25岁,超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止
-
实现步骤
-
创建学生对象
-
键盘录入姓名和年龄,并赋值给学生对象
-
如果是非法数据就再次录入
-
-
代码实现
学生类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
//当年龄不合法时,产生一个异常
throw new RuntimeException("年龄超出了范围");
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package pojo;
import java.util.Scanner;
public class ExceptionDemo12 {
public static void main(String[] args) {
// 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
// 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。
Student s = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入姓名");
String name = sc.nextLine();
s.setName(name);
while(true){
System.out.println("请输入年龄");
String ageStr = sc.nextLine();
try {
int age = Integer.parseInt(ageStr); //不能解析,匹配NumberFormatException异常
s.setAge(age); //超出范围,匹配RuntimeException异常
break; //年龄正常后,跳出循环
} catch (NumberFormatException e) {
System.out.println("请输入一个整数");
}catch (RuntimeException e){
System.out.println(e.getMessage());
}
}
System.out.println(s);
}
}
4.10 自定义异常
-
自定义异常概述
-
Java中定义的异常不能满足我们的需求时,我们可以自定义异常
-
自定义异常类必须继承Exception类或其子类
-
-
实现步骤
-
定义异常类,继承Exception或其子类
-
提供空参构造
-
提供带参构造
-
-
代码实现
自定义异常类型:代表学生年龄超出范围的异常
public class AgeOutOfBoundsException extends RuntimeException {
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
学生类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
//如果Java中提供的异常不能满足我们的需求,我们可以使用自定义的异常
throw new AgeOutOfBoundsException("年龄超出了范围");
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package pojo;
import java.util.Scanner;
public class ExceptionDemo12 {
public static void main(String[] args) {
// 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
// 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。
Student s = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入姓名");
String name = sc.nextLine();
s.setName(name);
while(true){
System.out.println("请输入年龄");
String ageStr = sc.nextLine();
try {
int age = Integer.parseInt(ageStr); //不能解析,匹配NumberFormatException异常
s.setAge(age); //超出范围,匹配RuntimeException异常
break; //年龄正常后,跳出循环
} catch (NumberFormatException e) {
System.out.println("请输入一个整数");
}catch (AgeOutOfBoundsException e){
System.out.println(e.getMessage());
}
}
System.out.println(s);
}
}
4.11 finally代码块
概述
-
:无论程序是否发生异常,还是使用return语句返回,finally代码块都会执行。
作用:
-
finally语句块一般用来编写 无论是否发生异常都必须执行的代码
如果在try...catch中执行了System.exit(0)语句,finally代码块才不会执行
-
System.exit(0)表示退出当前java虚拟机,java虚拟机停止了,任何代码就都不能执行了。