代码之家  ›  专栏  ›  技术社区  ›  Malax

最佳实践:hasxxx()方法,用于返回可能为空的getxxx()方法[已关闭]

  •  3
  • Malax  · 技术社区  · 15 年前

    这个问题可能看起来很简单,但我还没有找到答案,所以我在询问堆栈溢出社区。正如标题所示,我有一个带有几个getxxx()方法的类,其中一些方法可能返回空值。这是文档化的,此类的用户应该知道这一事实。

    为了简化这个类的使用,我想添加一些方便的hasxxx()方法,这些方法指示是否设置了特定的字段。首先,这似乎是个好主意…但后来人们想到了线程安全。

    由于此类的实例可能在线程间共享,因此属性的值可能会更改。众所周知,只有当我们知道在调用check方法之后状态不会改变时,check-then-act才可能发生,即使我们在执行check-then-act操作时被中断。

    我想到了以下解决方案:

    • 为此类的用户提供一种方法来“锁定”实例,以便在执行检查然后执行代码时更改状态。
    • 移除hasxxx()方法,因为它们对可变类无效。

    我不认为这是一个罕见的情况,所以一些会员可能已经在这个问题上存根,并找到了解决办法…

    福布尔肯

    10 回复  |  直到 15 年前
        1
  •  10
  •   Timothy Pratley    15 年前

    不需要使事情复杂化——用户知道是否设置了xxx,因为getxxx()返回空值。

    
    if ( (x=bar.getXXX()) ) {
       x.foo();
    }
    

    是解说

    
    if ( bar.hasXXX() ) {
      bar.getXXX().foo();
    }
    

    把hasxxx真正做的留给想象

        2
  •  5
  •   Michael Borgwardt    15 年前

    我肯定会把 hasXXX() 方法。锁定事物会造成死锁的可能性,而且不容易纠正(更不用说它可能造成的性能问题)。

    使用get方法和检查是否为空工作是一种简单、快速的方法,也是一种众所周知的方法。消除 NullPointerException S是一个有价值的事业,但往往是徒劳的。知道什么时候放弃它。

        3
  •  3
  •   Wim Coenen    15 年前

    检查然后行动是唯一可能的 如果我们知道国家不会 检查方法后更改 调用,即使我们被中断 在做检查的时候,做些动作。

    不管怎样,你会遇到这个问题,即使你只有 getXXX() 方法 :当线程A开始使用从中检索到的值执行某项操作时 GETXXX() ,线程B可能已经更改了字段。更糟的是,如果你不得不 getXXX getYYY 然后,您可能会对从未存在的事物有一个不一致的视图,因为对象在两个调用之间都发生了更改。

    对于可能随时被其他线程更改的字段,不应该有getter。唯一的例外是,当一个线程需要检查某个线程是否可用或由另一个线程完成时,例如,轮询用于线程之间通信的线程安全消息队列,或检查任务是否完成。

    通常,将锁定限制在一些用于在线程之间交换信息的选择类的内部实现上。不要在线程之间共享任何其他可变对象。

        4
  •  1
  •   Ty.    15 年前

    看看如何使该对象不可变,并在其中 HASXXX() 方法记录状态的对象。不确定这是否是一个选项,因为您可能已经在使用一个系统,但它也有助于良好的OO实践。

        5
  •  1
  •   agsamek    15 年前

    在500 KLoC Java项目中,我们使用TryGETXXX()语法来返回空值的方法。每个字段的名称中都有显式的空权限,并使用yyyornull语法进行编码。然后使用静态分析工具minik检查是否在不允许空值的分支中执行对对象的访问。

    不再有NPE问题:)

    所有结构的不可变性保证了线程的安全性。

    http://www.mimuw.edu.pl/.../JC-TS-AGS-AS_Minik-A-tool-for-maintaining-proper-Java-code-structure.pdf http://ocean.comarch.com/genrap/

        6
  •  1
  •   MSalters    15 年前

    C++解决方案是由 boost::optional<T> . 这可以防止意外的空指针取消引用:编译器强制您显式地处理 boost::none 案例。

        7
  •  0
  •   Justin Niessner    15 年前

    如果类的使用者知道如果不设置值,这些值将为空…那么我不担心提供 hasXXX() 方法。

    让使用者调用get方法,检查空值,并让他们相应地处理它。

        8
  •  0
  •   Wim ten Brink    15 年前

    只有当null是一个完全有效的值时,使用hasxxx()方法才是合乎逻辑的。基本上,hasxxx()只会实际地说它甚至没有要返回的空值。如果hasxxx()只是用来检查getxxx()是否返回空值,那么您的逻辑有问题,您将非常需要来自星球Vulcan的人!;-)

    has/getxxx()组合的另一个问题是hasxxx()可能表示它有一个值,但另一个线程刚刚释放了数据,因此getxxx()将返回空值。这将是一个严重的线程问题,您只能通过在整个has/getxxx()代码块周围添加一个锁来解决。

    不过,您可以通过创建一个组合函数来解决这个问题,该函数可以调用biggetxxx(),该函数首先设置锁,调用hasxxx()检查值,然后调用getxxx()检索值。如果没有值,它将返回空值,因此调用方必须检查值空值… 但是,这是没有意义的,因为您可以调用getxxx()立即获得结果或空值。:-)或添加一个bighasxxx()方法,该方法将检查biggetxxx()是否返回空值。然后您将围绕这些内容创建一个新的函数,这样就可以再次保证线程安全。例如verybiggetxxx()…这样的代码层数是没有尽头的…

    只需终止hasxxx()方法即可。 它们毫无用处。

        9
  •  0
  •   David R Tribble    15 年前

    1. 如果你 getXxx() 方法允许返回空值 即使成员已设置 (例如,对于一个显式的空值),那么您需要其他方法来告诉外部世界成员已经被设置。

    我将返回一个特殊的常量值来指示“已设置但为空”。例如:

    public class Foo
    {
        public static final String  NULL_STRING = "Foo.NULL_STRING";
    
        private String  m_bar;
    
        public void setBar(String v)
        {
            if (v == null)
                v = NULL_STRING;
            m_bar = v;
        }
    
        public String getBar()
        {
            return m_bar;
        }
    }
    

    只要你不 实习生 返回的字符串值, getBar() 方法将只返回等于(即 参考 等于) NULL_STRING 如果 m_bar 成员已显式设置为空。方法将返回 null 只有当成员 被设定。

    或者,您可以反向使用该技术,这样一个特殊的值(例如 STRING_NOT_SET )如果成员 已经设定好了,就回来吧 无效的 如果成员设置为 无效的 明确地说。

    public class Foo2
    {
        public static final String  STRING_NOT_SET = "Foo.STRING_NOT_SET";
    
        private String  m_bar = STRING_NOT_SET;
    
        public void setBar(String v)
        {
            m_bar = v;
        }
    
        public String getBar()
        {
            return m_bar;
        }
    }
    
        10
  •  0
  •   mfx    15 年前

    有两个可能的原因介绍 hasXXX() :

    • 因为 HASXXX() getXXX() != null ,因此可以认为可读性更好。
    • 因为 getXXX() 方法可能很昂贵,有时只有布尔值 HASXXX() -需要信息

    如果你通常需要 GETXXX() 不管怎样, HASXXX() 毫无意义。