Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 检查变量是否等于/不等于null是正确的吗?取决于上下文?_Java_Null - Fatal编程技术网

Java 检查变量是否等于/不等于null是正确的吗?取决于上下文?

Java 检查变量是否等于/不等于null是正确的吗?取决于上下文?,java,null,Java,Null,是这样吗 示例代码: void foo(E param){ if(param == null){ // do this }else{ // do that } //... } 首先,我读了一些帖子,其中有人讨论允许变量为null会增加软件的复杂性,所以我想努力尝试回答这个问题,忘记这一点 我的想法 作为一个初学者,我的想法可能是错误的,但我希望你能帮我澄清这一点 我认为根据变量所在的上下文,检查变量是否为null是正确的,让我用一个例子

是这样吗

示例代码:

void foo(E param){

    if(param == null){
        // do this
    }else{
        // do that
    }
//...
}
首先,我读了一些帖子,其中有人讨论允许变量为null会增加软件的复杂性,所以我想努力尝试回答这个问题,忘记这一点

我的想法

作为一个初学者,我的想法可能是错误的,但我希望你能帮我澄清这一点

我认为根据变量所在的上下文,检查变量是否为null是正确的,让我用一个例子来解释:

使用不当:

我们的项目实现了命令模式,我们有一套指令。然后我们在控制台中写一条指令,我们必须解释它。我们有一个解释器类,它试图解析它,因此如果解释器找不到合适的指令,它将返回null

代码示例:

public class Interpreter {

    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private static final List<Instruction> listInstructions = loadInstructions();


    /**
     * Generates a new instruction according to the user input
     * @param line - A string with the user input
     * @return The instruction read from the given line. If the instruction is not correct, then it returns null.
     */
    public static Instruction generateInstruction(String line) throws WrongInstructionFormatException
    {
        Instruction instru = null;
        Iterator<Instruction> it = listInstructions.iterator();
        int i = 0;
        while(it.hasNext() && i <9 && instru == null)
        {
            try
            {
                instru = it.next().parse(line);
            }
            catch(WrongInstructionFormatException e)
            {

            }
            finally
            {
                i++;
            }
        }
        return instru;
     }
//...




public class MainClass
{
    /**
     * MainFunction
     */
        public void mainFuction()
        {

            Instruction instru;
            while(true)
            {
                instru = Interpreter.generateInstruction(orden);
                if(instru == null) <------
                    // Error.
                else
                    instru.execute();

            }

        }
  }
在这种情况下,我认为我们实现了这个错误,因为解释器不能返回null,而是返回一个异常,因为在我看来,上下文中的变量永远不能为null。我希望我是清楚的,如果不是这样,我想稍后用你的评论来澄清

正确使用:已编辑

我们项目的主类有一组属性,可以从中实例化或不实例化。根据我们是否实例化了一个,两个或两个都没有,将有一组函数来执行一个、两个或不执行任何操作

public class MainClass extends Observable
{
    private A a;
    private B b; // This attribute allows you to start making a log in a txt file
    private C c; // This attribute allows you to start making a log in a DB

    public MainClass(A a){ //....}
    public MainClass(A a, B b) { // .....}
    public MainClass(A a, C c) { // .....}
    public MainClass(A a, B b, C c){ //.....}


    public void log(String update)
    {
        if(this.b != null) <-----
            // Save the update in the txt file
        if(this.c != null) <-----
            // Save the update in a db row
    }
}
那么,为什么这是正确的呢?我认为这是正确的,因为属性可能有空值,而不像前面的情况


这就开始了讨论,如果其他人有同样的疑问,我希望它能帮助他们。

当情况是预期的和/或可恢复的,抛出异常与返回null几乎完全是风格问题。你提出的论点是很好的区分,如果它们对你有意义的话,那么我说去做吧


当然,这并不是说你应该使用异常作为一种进入流控制工具,但在你描述的那种情况下,它听起来非常合理。

当这种情况是预期的和/或可恢复的,抛出异常与返回null几乎完全是一个风格问题。你提出的论点是很好的区分,如果它们对你有意义的话,那么我说去做吧


当然,这并不是说您应该使用异常作为一种转到流控制工具,但在您描述的这种情况下,它听起来非常合理。

关于null的建议不是不检查它们,而是不生成或允许它们。显然,如果程序中有空值,则需要检查它们

在第二个示例中,遵循建议的方法是找到一种实现类的方法,使其不具有可为空的字段。为什么类具有可选属性?它与这些属性有什么关系?是否有一种方法可以通过将类拆分为多个类来构造该类,从而使其不具有可选属性

在第二个示例中,您正在if测试中使用属性的空性。面向对象设计中的一个标准做法是用多态性替换条件。你能试试吗

编辑:好的,下面是我如何使用多态性解决第二种情况。我删除了字段a,因为它与本例无关

public class MainClass extends Observable {
    private final Collection<? extends LogDestination> logDestinations;

    public MainClass() {
        logDestinations = Collections.emptySet();
    }

    public MainClass(B b) {
        logDestinations = Collections.singleton(new TextFileLog(b));
    }

    public MainClass(C c) {
        logDestinations = Collections.singleton(new DatabaseLog(c));
    }

    public MainClass(B b, C c) {
        logDestinations = Arrays.asList(new TextFileLog(b), new DatabaseLog(c));
    }

    public void log(String update) {
        for (LogDestination logDestination : logDestinations) {
            logDestination.log(update);
        }
    }
}

interface LogDestination {
    public void log(String update);
}

class TextFileLog implements LogDestination {
    private final B b;

    public TextFileLog(B b) {
        this.b = b;
    }

    @Override
    public void log(String update) {
        // Save the update in the txt file
    }
}

class DatabaseLog implements LogDestination {
    private final C c;

    public DatabaseLog(C c) {
        this.c = c;
    }

    @Override
    public void log(String update) {
        // Save the update in a db row
    }
}

抽象地说,这是在将逻辑中唯一的备选方案以选择要创建的LogDestination的形式推送到构造函数中。一旦创建了它们,就可以完全统一地处理它们,多态性将一般调用分派给特定方法。由于设置对象的不同方式有不同的构造函数,因此根本不需要任何条件逻辑。

关于null的建议不是不检查它们,而是不生成或允许它们。显然,如果程序中有空值,则需要检查它们

在第二个示例中,遵循建议的方法是找到一种实现类的方法,使其不具有可为空的字段。为什么类具有可选属性?它与这些属性有什么关系?是否有一种方法可以通过将类拆分为多个类来构造该类,从而使其不具有可选属性

在第二个示例中,您正在if测试中使用属性的空性。面向对象设计中的一个标准做法是用多态性替换条件。你能试试吗

编辑:好的,下面是我如何使用多态性解决第二种情况。我删除了字段a,因为它与本例无关

public class MainClass extends Observable {
    private final Collection<? extends LogDestination> logDestinations;

    public MainClass() {
        logDestinations = Collections.emptySet();
    }

    public MainClass(B b) {
        logDestinations = Collections.singleton(new TextFileLog(b));
    }

    public MainClass(C c) {
        logDestinations = Collections.singleton(new DatabaseLog(c));
    }

    public MainClass(B b, C c) {
        logDestinations = Arrays.asList(new TextFileLog(b), new DatabaseLog(c));
    }

    public void log(String update) {
        for (LogDestination logDestination : logDestinations) {
            logDestination.log(update);
        }
    }
}

interface LogDestination {
    public void log(String update);
}

class TextFileLog implements LogDestination {
    private final B b;

    public TextFileLog(B b) {
        this.b = b;
    }

    @Override
    public void log(String update) {
        // Save the update in the txt file
    }
}

class DatabaseLog implements LogDestination {
    private final C c;

    public DatabaseLog(C c) {
        this.c = c;
    }

    @Override
    public void log(String update) {
        // Save the update in a db row
    }
}
抽象地说,这是在将逻辑中唯一的备选方案以选择哪个目的地的形式一直推到构造函数中
创造。一旦创建了它们,就可以完全统一地处理它们,多态性将一般调用分派给特定方法。由于设置对象的不同方式有不同的构造函数,因此根本不需要任何条件逻辑。

我有一个拥有2000多个类的程序。假设每个类大约有20个函数,即40000个函数。它们中的很多在每个示例中只有几行代码:get/set函数。如果每个函数都检查了空参数等,那么大量代码只用于验证,对于处理的大量异常,可以使用类似的参数。此外,如果我只检查空值,我还可以进行完全验证以确保javadoc契约得到满足。例如,迭代传递给函数的对象列表,检查空值、范围问题等。请注意,这种方法会出现性能问题

相反,我更希望有一个适用于整个项目的约定策略,即不允许函数的参数为null,或者返回值为null,除非在javadoc契约设计中指定。调用方有责任遵守javadoc契约,并在调用我的函数之前进行任何验证检查。但是,我将考虑构造函数的验证检查,这些构造函数采用不止一个参数来确保不创建不完整的对象,以及一些函数,它们在处理输入参数时过于复杂。注意,函数的直接调用方不必在调用函数之前进行验证检查。相反,在调用链的某个地方,至少有一个其他函数需要这样做。
注意:我看到网上有很多关于如何正确处理这些问题的争论。

我有一个有2000多个课程的程序。假设每个类大约有20个函数,即40000个函数。它们中的很多在每个示例中只有几行代码:get/set函数。如果每个函数都检查了空参数等,那么大量代码只用于验证,对于处理的大量异常,可以使用类似的参数。此外,如果我只检查空值,我还可以进行完全验证以确保javadoc契约得到满足。例如,迭代传递给函数的对象列表,检查空值、范围问题等。请注意,这种方法会出现性能问题

相反,我更希望有一个适用于整个项目的约定策略,即不允许函数的参数为null,或者返回值为null,除非在javadoc契约设计中指定。调用方有责任遵守javadoc契约,并在调用我的函数之前进行任何验证检查。但是,我将考虑构造函数的验证检查,这些构造函数采用不止一个参数来确保不创建不完整的对象,以及一些函数,它们在处理输入参数时过于复杂。注意,函数的直接调用方不必在调用函数之前进行验证检查。相反,在调用链的某个地方,至少有一个其他函数需要这样做。
注意:我在网上看到,关于如何正确处理这一切,存在很多争论。

如果它可以为空,那么检查它是否为空。例外与无效是一个观点和风格的问题,当情况可以恢复时,你的例子引人注目的是,你的第一个例子非常具体,你得出结论,最好抛出一个例外,而你的第二个则相当模糊,你没有得出这个结论。对第二个例子进行更详细的研究会很有趣,看看您是否仍然这样认为。不检查传入引用参数是否为null有两种情况:1您完全控制所有调用者,并确保实际参数从不为null,或者2对于null,没有什么比从引用首次用作指针的位置抛出NullPointerException更有用的了。此外,如果这样做:if null!=someVar和/或if.equalssomeVar您可以避免NPEOkey,我现在将在第二个示例中使用它。如果它可以为null,则检查它是否为null。例外与无效是一个观点和风格的问题,当情况可以恢复时,你的例子引人注目的是,你的第一个例子非常具体,你得出结论,最好抛出一个例外,而你的第二个则相当模糊,你没有得出这个结论。对第二个例子进行更详细的研究会很有趣,看看您是否仍然这样认为。不检查传入引用参数是否为null有两种情况:1您完全控制所有调用者,并确保实际参数从不为null,或者2对于null,没有什么比从whe抛出NullPointerException更有用的了

reference首先用作指针。如果使用:if null!=someVar和/或if.equalssomeVar您可以避免NPEOkey,我现在将在第二个示例中使用它。它不仅仅是样式。抛出异常会影响性能。最好在预期的情况下避免它。@手册除非您将异常用作循环或其他内容中的流控制工具,否则性能影响应该可以忽略不计。我无法想象一个非人为的例子,其中性能差异特别有意义。此外,Java精确地检查了预期情况下的异常,因此我认为这在很大程度上是风格问题,而不是简单的正确性问题。有许多性能关键型应用程序需要每秒处理10k或100k事务—金融、医疗成像、在线游戏、智能计量等。。如果这些交易中有很大一部分是抛售交易,我相信其影响将是巨大的。我真的只是在为那些规模宏大的惯例辩护。谢谢你的回答。这不仅仅是风格。抛出异常会影响性能。最好在预期的情况下避免它。@手册除非您将异常用作循环或其他内容中的流控制工具,否则性能影响应该可以忽略不计。我无法想象一个非人为的例子,其中性能差异特别有意义。此外,Java精确地检查了预期情况下的异常,因此我认为这在很大程度上是风格问题,而不是简单的正确性问题。有许多性能关键型应用程序需要每秒处理10k或100k事务—金融、医疗成像、在线游戏、智能计量等。。如果这些交易中有很大一部分是抛售交易,我相信其影响将是巨大的。我真的只是在为可伸缩性好的约定辩护。谢谢你的回答。我有疑问,想象一下我的主要类属性是用来保存软件日志的。我可以在db或文本文件中保存或不保存信息,也可以两者都不保存。我应该如何用多态性实现这一点?实际上,我会在第二个例子中实现它,你的建议是什么?那么在这个例子中,属性是什么?日志文件名和数据库URL或其他什么?属性是对执行任务的类的引用,调用X方法。对于延迟,我深表歉意,但我已经抽出时间来演示如何执行此操作。没问题,谢谢,我已经做了类似的操作来解决其他问题,但没有看到如何在此处应用我有疑问,假设我的主要类属性用于保存软件日志。我可以在db或文本文件中保存或不保存信息,也可以两者都不保存。我应该如何用多态性实现这一点?实际上,我会在第二个例子中实现它,你的建议是什么?那么在这个例子中,属性是什么?日志文件名和数据库URL或其他什么?属性是对执行此任务的类的引用,调用X方法。对于延迟,我深表歉意,但我已经抽出时间来演示如何执行此操作。没问题,谢谢,我已经做了类似的操作来解决其他问题,但没有看到如何在此处应用