案例有3中情形使用Objects.requireNonNull
- 第1种情形有2种,都是直接复制,一个通过构造函数,一个通过设置函数
- 第2中情形是验证的引用没有调用,但是不过不验证,再之后调用对象方法会导致空指针异常,无法查询空指针的赋值点。
- 第3种情形是虽然对引用调用有函数调用,会导致异常,感觉可以不用验证。但是可能导致对象状态的修改。但调用是失败的。
package org.ziegler.javabase.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class RequiredNonNullSample {
private Ball ball;
private List<Ball> ballBucket = new ArrayList<>();
RequiredNonNullSample(Ball ball) {
// 情形1.1:赋值的第一时间验证。使用时验证,不容易查询空引用异常
this.ball = Objects.requireNonNull(ball);
}
void setBall(Ball ball) {
// 情形1.2:赋值的第一时间验证。使用时验证,不容易查询空引用异常
this.ball = Objects.requireNonNull(ball);
}
void addBall(Ball ball) {
// 情形2:第一时间验证对象是否为{@code null}
Objects.requireNonNull(ball, "ball is null");
ballBucket.add(ball);
}
void showBallBucket() {
ballBucket.forEach(Ball::printBall);
}
/**
* 将2个{@link Ball}的尺寸都设置为相同值{@code size}
* @param ball1 不能为{@code null}
* @param ball2 不能为{@code null}
* @param size
* @throws NullPointerException 参数为{@code ball1 == null}或者{@code ball2 == null}
*/
public static void setBallSameSize(Ball ball1, Ball ball2, int size) {
/**
* 情形3:
* 这种调用方式如果不调用Objects.requireNonNull,是不是也可以呢?
* 因为调用Ball对象的{@link Ball#setSize(int)} ()}方法也会抛出异常。
* 但是如果{@code ball2 == null}那么会导致ball1的状态改变,但是调用
* {@code ball2.setSize(size);}抛出异常
* 没能达到这个函数的要求,同时设置2个球的size,只改变了第一个Ball的尺寸,
* 并且在发生异常之后,没能回滚操作。但通过Objects.requireNonNull验证就可以避免。
* 总结:前置的Objects.requireNonNull验证,防止破坏对象状态,在第一时间发现异常。
*/
Objects.requireNonNull(ball1, "ball1 is null");
Objects.requireNonNull(ball2, "ball2 is null");
ball1.setSize(size);
ball2.setSize(size);
}
/**
* 上面方法的错误写法
* @param ball1
* @param ball2
* @param size
*/
@Deprecated
public static void setBallSameSizeDeprecated(Ball ball1, Ball ball2, int size) {
/**
* 这种调用方式如果不调用Objects.requireNonNull,是不是也可以呢?
* 因为调用Ball对象的{@link Ball#setSize(int)} ()}方法也会抛出异常。
* 但是如果{@code ball2 == null}那么会导致ball1的状态改变,但是调用
* {@code ball2.setSize(size);}抛出异常
* 没能达到这个函数的要求,同时设置2个球的size,只改变了第一个Ball的尺寸,
* 并且在发生异常之后,没能回滚操作。但通过Objects.requireNonNull验证就可以避免。
*/
ball1.setSize(size);
ball2.setSize(size);
}
public void printBall() {
// 因为在引用赋值的时候已经验证了ball有效,所以调用可以不验证
ball.printBall();
}
public static class Ball {
private int size;
public Ball(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public void printBall() {
System.out.println("ball - size = " + getSize());
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Ball{");
sb.append("size=").append(size);
sb.append('}');
return sb.toString();
}
}
public static void main(String[] args) {
Ball defaultBall = new Ball(8);
Ball ball1 = new Ball(5);
Ball ball2 = new Ball(11);
RequiredNonNullSample requiredNonNullSample = new RequiredNonNullSample(defaultBall);
requiredNonNullSample.printBall();
requiredNonNullSample.setBall(ball1);
requiredNonNullSample.printBall();
requiredNonNullSample.addBall(ball1);
requiredNonNullSample.addBall(ball2);
requiredNonNullSample.showBallBucket();
setBallSameSizeTest();
setBallSameSizeDeprecatedTest();
}
static void setBallSameSizeTest() {
Ball ballA = new Ball(5);
Ball ballB = null;
try {
setBallSameSize(ballA, ballB, 10);
} catch (RuntimeException e) {
System.out.println("e = " + e);
}
ballA.printBall();
}
static void setBallSameSizeDeprecatedTest() {
Ball ballA = new Ball(5);
Ball ballB = null;
try {
setBallSameSizeDeprecated(ballA, ballB, 10);
} catch (RuntimeException e) {
System.out.println("e = " + e);
}
ballA.printBall();
}
}
输出结果:
ball - size = 8
ball - size = 5
ball - size = 5
ball - size = 11
e = java.lang.NullPointerException: ball2 is null
ball - size = 5
e = java.lang.NullPointerException
ball - size = 10