对象空指针
//理解什么是空指针
public class WhatIsNpe {
public static class User {
private String name;
private String[] address;
public void print() {
System.out.println("This is User Class!");
}
public String readBook() {
System.out.println("User Read Imooc Escape!");
return null;
}
}
//自定义一个运行时异常
public static class CustomException extends RuntimeException {}
public static void main(String[] args) {
// 第一种情况: 调用了空对象的实例方法
// User user = null;
// user.print();
// 第二种情况: 访问了空对象的属性
// User user = null;
// System.out.println(user.name);
// 第三种情况: 当数组是一个空对象的时候, 取它的长度
// User user = new User();
// System.out.println(user.address.length);
// 第四种情况: null 当做 Throwable 的值
// CustomException exception = null;
// throw exception;
// 第五种情况: 方法的返回值是 null, 调用方直接去使用
User user = new User();
System.out.println(user.readBook().contains("MySQL"));
}
}
变量赋值自动拆箱出现的空指针
方法传参时自动拆箱出现的空指针
基本数据类型优于包装器类型,优先考虑使用基本类型
对于不确定的包装器类型,一定要校验是否是null
对于值为null的包装器类型,赋值为0
//自动拆箱引发的空指针问题
@SuppressWarnings("all")
public class UnboxingNpe {
private static int add(int x, int y) {
return x + y;
}
private static boolean compare(long x, long y) {
return x >= y;
}
public static void main(String[] args) {
// 1. 变量赋值自动拆箱出现的空指针
// javac UnboxingNpe.java
// javap -c UnboxingNpe.class
Long count = null;
long count_ = count;
// 2. 方法传参时自动拆箱引发的空指针
// Integer left = null;
// Integer right = null;
// System.out.println(add(left, right));
// 3. 用于大小比较的场景
// Long left = 10L;
// Long right = null;
// System.out.println(compare(left, right));
}
}
字符串使用equals时出现空指针
对象数组虽然new出来了,但是如果没有初始化,一样会出现空指针
list对象add null不报错,但是addAll不能添加null,否则NPE
//字符串、数组、集合在使用时出现空指针
@SuppressWarnings("all")
public class BasicUsageNpe {
private static boolean stringEquals(String x, String y) {
return x.equals(y);
}
public static class User {
private String name;
}
public static void main(String[] args) {
// 1. 字符串使用 equals 可能会报空指针错误
// System.out.println(stringEquals("xyz", null));
// System.out.println(stringEquals(null, "xyz"));
// 2. 对象数组 new 出来, 但是元素没有初始化
// User[] users = new User[10];
// for (int i = 0; i != 10; ++i) {
// users[i] = new User();
// users[i].name = "imooc-" + i;
// }
// 3. List 对象 addAll 传递 null 会抛出空指针
List<User> users = new ArrayList<User>();
User user = null;
List<User> users_ = null;
users.add(user);
users.addAll(users_);
}
}
手动脱敏:直接在业务逻辑层代码中对敏感数据进行逐一处理,这种方式虽然提供了较高的灵活性,但容易因人为疏忽而导致脱敏遗漏,同时也会导致代码中存在大量的重复处理逻辑,增加了维护成本。
AOP(面向切面编程):利用AOP技术,通过定义切面来拦截API接口返回的数据流,从而实现对敏感字段的统一处理。这种方法能够将脱敏逻辑从业务代码中抽离出来,实现集中管理,提高了代码的可维护性和可扩展性。然而,由于AOP的拦截机制会增加一定的处理开销,因此可能会对系统性能产生一定的影响。
自定义序列化器:在数据序列化阶段,通过集成JSON序列化框架(如Jackson)提供的自定义序列化器功能,实现对敏感字段的自动化处理。这种方法既保持了较好的性能表现,又能够将脱敏逻辑与业务逻辑完全解耦,使得代码更加清晰和易于管理。
注解+反射:通过定义自定义注解来标记那些需要进行脱敏处理的字段,然后在数据返回前,利用Java的反射机制在运行时动态地遍历这些字段并进行脱敏处理。这种方式简化了脱敏操作的使用过程,使得开发者只需通过简单的注解标记即可实现脱敏功能,同时也有利于后续对脱敏逻辑的维护和扩展。