将空值作为参数传递给方法时如何修复 NullPointerException [重复]
Posted
技术标签:
【中文标题】将空值作为参数传递给方法时如何修复 NullPointerException [重复]【英文标题】:How to fix a NullPointerException when passing null values as arguments to a method [duplicate] 【发布时间】:2020-01-10 02:18:19 【问题描述】:我的目标是使用自动生成测试以查找这些错误的工具来修复几个 Java 类中的错误。一个错误是 NullPointerException,它是因为两个属性被初始化为 null 并传递给一个对象而引起的。同样,这是由工具自动生成的,所以我的目标是修复类文件。
这是工具生成的代码:
public void test1() throws Throwable
if (debug)
System.out.format("%n%s%n", "ErrorTest0.test1");
Point point0 = null;
Point point1 = null;
Line line2 = new Line(point0, point1); // Line 16
这是导致问题的构造函数:
public Line(Point p1, Point p2)
this.point1 = new Point(p1.x,p1.y); // Line 17
this.point2 = new Point(p2.x,p2.y);
Point 的构造函数:
public Point(double x, double y)
this.x = x;
this.y = y;
这是我从工具中得到的错误消息:
java.lang.NullPointerException
at Line.<init>(Line.java:17)
at ErrorTest0.test1(ErrorTest0.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.runner.JUnitCore.runMain(JUnitCore.java:77)
at org.junit.runner.JUnitCore.main(JUnitCore.java:36)
我猜我应该在构造函数中包含一些不允许 this 为空的东西?
【问题讨论】:
null
表示无效值;两个无效点之间的线应该是什么样子?有效点和无效点之间呢?
将 null 传递给构造函数是否有意义?如果这是我的代码,我会测试 null,如果存在,抛出我自己的自定义异常,我会处理一个最好的方法
初始化您的Point
实例,然后将它们作为参数传递给Line
-type 对象
好吧,imo这不是测试,因为没有断言。所以你需要添加一些断言。关于空值,你必须决定你想要什么,要么抛出异常(我会这样做),要么抑制它并且不初始化字段(我认为这是一个糟糕的设计)。
还可以看看这个软件工程堆栈交换答案:Best way to handle nulls in Java?
【参考方案1】:
您可以使用三种方法来更新 line 方法。希望这些会被您的测试工具拾取。
要求构造函数中的参数不为空。这是更现代的方法。
public Line(@NotNull Point p1, @NotNull Point p2)
this.point1 = Objects.requireNonNull(p1);
this.point2 = Objects.requireNonNull(p2);
当参数设置为空时抛出异常。您的测试用例应该允许您预期该用例会出现异常。
public Line(Point p1, Point p2) throws IllegalArgumentException
if (p1 == null || p2 == null)
throw new IllegalArgumentException("point cannot be null");
this.point1 = p1;
this.point2 = p2;
在传入 null 时有一个合理的默认行为。什么是合理的完全取决于您的用例。
public Line(Point p1, Point p2)
if (p1 != null)
this.point1 = p1;
else
this.point1 = new Point(0.0, 0.0);
if (p2 != null)
this.point2 = p2;
else
this.point2 = new Point(0.0, 0.0);
【讨论】:
【参考方案2】:够了吗?
public Line(Point p1, Point p2)
if (p1 == null || p2 == null)
throw new IllegalArgumentException("One or both points are null");
this.point1 = new Point(p1.x,p1.y);
this.point2 = new Point(p2.x,p2.y);
您正在尝试访问未初始化的类的字段。
【讨论】:
恐怕这真的没有解释什么,也没有深入探讨。 当点为空时你想看到什么结果?通常,在这种情况下,抛出一个IllegalArgumentException
。
现在如果一个(或两个)通过的点是null
,你会默默地创建一个未定义状态的 Line 对象,它会在一段时间后崩溃。你只是在隐藏问题,让调试变得更加困难。
正如我上面所说的——这完全取决于作者想要什么。但是,我同意这不是最好的解决方案
然后改进答案以处理这些突发事件(或删除此答案)。有关此示例,请参阅 CheeseFerret 的回答。以上是关于将空值作为参数传递给方法时如何修复 NullPointerException [重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何将空参数传递给 msdeploy powershell deploy 命令