目录
Java空指针和异常
2-1
常犯指数5星
NullPointException
运行时异常的一个子类
- 对象没有初始化就去使用了
- 访问了空对象的属性
- 当数组是一个空对象时,取长度
- null当做Throwable的值
- 方法的返回值是null,调用方法直接去使用
拆装箱引发的空指针:
2-2
javac jdk编译java的源代码的工具,用于生成源代码class文件
javap jdk自带的反解析文件
2-3
空对象调用equals方法,所以null放后面
调用equals的对象不为空,即前面的x
对象数组new出来,但是元素没有初始化
list对象addAll传递null会抛出空指针
2-4
友情链接
package com.imooc.java.escape;
import java.util.Optional;
/**
* <h1>学会 Optional, 规避空指针异常</h1>
* */
@SuppressWarnings("all")
public class OptionalUsage {
private static void badUsageOptional() {
Optional<User> optional = Optional.ofNullable(null);
User user = optional.orElse(null); // good
user = optional.isPresent() ? optional.get() : null; // bad
}
public static class User {
private String name;
public String getName() {
return name;
}
}
private static void isUserEqualNull() {
User user = null;
if (user != null) {
System.out.println("User is not null");
} else {
System.out.println("User is null");
}
Optional<User> optional = Optional.empty();
if (optional.isPresent()) {
System.out.println("User is not null");
} else {
System.out.println("User is null");
}
}
private static User anoymos() {
return new User();
}
public static void main(String[] args) {
// 没有意义的使用方法
isUserEqualNull();
User user = null;
Optional<User> optionalUser = Optional.ofNullable(user);
// 存在即返回, 空则提供默认值
optionalUser.orElse(new User());
// 存在即返回, 空则由函数去产生
optionalUser.orElseGet(() -> anoymos());
// 存在即返回, 否则抛出异常
optionalUser.orElseThrow(RuntimeException::new);
// 存在才去做相应的处理
optionalUser.ifPresent(u -> System.out.println(u.getName()));
// map 可以对 Optional 中的对象执行某种操作, 且会返回一个 Optional 对象
optionalUser.map(u -> u.getName()).orElse("anymos");
// map 是可以无限级联操作的
optionalUser.map(u -> u.getName()).map(name -> name.length()).orElse(0);
}
}
2-5
运行时异常+检查性异常
package com.imooc.java.escape;
/**
* <h1>Java 异常处理</h1>
* */
@SuppressWarnings("all")
public class ExceptionProcess {
private static class User {}
/**
* <h2>Java 异常本质 -- 抛出异常</h2>
* */
private void throwException() {
User user = null;
// ....
if (null == user) {
throw new NullPointerException();
}
}
/**
* <h2>不能捕获空指针异常</h2>
* */
private void canNotCatchNpeException() {
try {
throwException();
} catch (ClassCastException cce) {
System.out.println(cce.getMessage());
System.out.println(cce.getClass().getName());
}
}
/**
* <h2>能够捕获空指针异常</h2>
* */
private void canCatchNpeException() {
try {
throwException();
} catch (ClassCastException cce) {
System.out.println(cce.getMessage());
System.out.println(cce.getClass().getName());
} catch (NullPointerException npe) {
System.out.println(npe.getMessage());
System.out.println(npe.getClass().getName());
}
}
public static void main(String[] args) {
ExceptionProcess process = new ExceptionProcess();
process.canCatchNpeException();
System.out.println("程序不会终止");
// process.canNotCatchNpeException();
}
}
运行结果:
null
java.lang.NullPointerException
程序不会终止
正确的抛出异常和正确的捕获异常,才能使程序健康的运行下去。
2-6
2-7
ClassCastException 类型转换异常
不要在迭代器里对list做modify操作,会引发快速失败机制报错
枚举类异常处理
package com.imooc.java.escape;
import com.google.common.base.Enums;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* <h1>编码中的常见的异常</h1>
* */
@SuppressWarnings("all")
public class GeneralException {
public static class User {
private String name;
public User() {}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Manager extends User {}
public static class Worker extends User {}
private static final Map<String, StaffType> typeIndex = new HashMap<>(
StaffType.values().length
);
static {
for (StaffType value : StaffType.values()) {
typeIndex.put(value.name(), value);
}
}
private static void concurrentModificationException(ArrayList<User> users) {
// 直接使用 for 循环会触发并发修改异常
// for (User user : users) {
// if (user.getName().equals("imooc")) {
// users.remove(user);
// }
// }
// 使用迭代器则没有问题
Iterator<User> iter = users.iterator();
while (iter.hasNext()) {
User user = iter.next();
if (user.getName().equals("imooc")) {
iter.remove();
}
}
}
private static StaffType enumFind(String type) {
// return StaffType.valueOf(type);
// 1. 最普通、最简单的实现
// try {
// return StaffType.valueOf(type);
// } catch (IllegalArgumentException ex) {
// return null;
// }
// 2. 改进的实现, 但是效率不高
// for (StaffType value : StaffType.values()) {
// if (value.name().equals(type)) {
// return value;
// }
// }
// return null;
// 3. 静态 Map 索引, 只有一次循环枚举的过程
// return typeIndex.get(type);
// 4. 使用 Google Guava Enums, 需要相关的依赖
return Enums.getIfPresent(StaffType.class, type).orNull();
}
public static void main(String[] args) {
// 1. 并发修改异常
// ArrayList<User> users = new ArrayList<User>(
// Arrays.asList(new User("qinyi"), new User("imooc"))
// );
// concurrentModificationException(users);
// 2. 类型转换异常
// User user1 = new Manager();
// User user2 = new Worker();
// Manager m1 = (Manager) user1;
// Manager m2 = (Manager) user2;
// System.out.println(user2.getClass().getName());
// System.out.println(user2 instanceof Manager);
// 3. 枚举查找异常
System.out.println(enumFind("RD"));
System.out.println(enumFind("abc"));
}
}
以上
注意:使用map index索引的方式遍历enum,并使用guava工具包改进
2-8
传统try finally的缺点
使用 try with resources
package com.imooc.java.escape.try_with_resources;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.Buffer;
/**
* <h1>解决使用 try finally 的资源泄露隐患</h1>
* */
public class Main {
/**
* <h2>传统的方式实现对资源的关闭</h2>
* */
private String traditionalTryCatch() throws IOException {
// 1. 单一资源的关闭
// String line = null;
// BufferedReader br = new BufferedReader(new FileReader(""));
// try {
// line = br.readLine();
// } finally {
// br.close();
// }
// return line;
// 2. 多个资源的关闭
// 第一个资源
InputStream in = new FileInputStream("");
try {
// 第二个资源
OutputStream out = new FileOutputStream("");
try {
byte[] buf = new byte[100];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
return null;
}
/**
* <h2>java7 引入的 try with resources 实现自动的资源关闭</h2>
* */
private String newTryWithResources() throws IOException {
// 1. 单个资源的使用与关闭
// try (BufferedReader br = new BufferedReader(new FileReader(""))) {
// return br.readLine();
// }
// 2. 多个资源的使用与关闭
try (FileInputStream in = new FileInputStream("");
FileOutputStream out = new FileOutputStream("")
) {
byte[] buffer = new byte[100];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
}
return null;
}
public static void main(String[] args) throws MyException {
// AutoClose autoClose = new AutoClose();
// try {
// autoClose.work();
// } finally {
// autoClose.close();
// }
try (AutoClose autoClose = new AutoClose()) {
autoClose.work();
}
}
}
package com.imooc.java.escape.try_with_resources;
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
package com.imooc.java.escape.try_with_resources;
public class AutoClose implements AutoCloseable {
@Override
public void close() {
System.out.println(">>> close()");
throw new RuntimeException("Exception in close()");
}
public void work() throws MyException {
System.out.println(">>> work()");
throw new MyException("Exception in work()");
}
}