将空值作为参数传递给方法时如何修复 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 命令

使用 @Query JPA 注释将空参数传递给本机查询

如何将json POST数据作为对象传递给Web API方法?

VBScript:将具有空值的参数传递给存储过程?

如何将类对象作为参数传递给不同的类方法?

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?