【问题标题】:Best practice of using flags in Java method在 Java 方法中使用标志的最佳实践
【发布时间】:2011-08-29 17:21:18
【问题描述】:

在 Java 方法中指定标志的最佳做法是什么?

我见过 SWT 使用 int 作为位域,例如:

(示例部分来自“Effective Java, 2nd Ed.”第 159 页):

public class Text {
  public static final int STYLE_BOLD = 1 << 0; // 1
  public static final int STYLE_ITALIC = 1 << 1; // 2

  void printText(String text, int flags) {

  }
}

你的客户电话看起来像:

printText("hello", Text.STYLE_BOLD | Text.STYLE_ITALIC);

..但不鼓励这样做,因为您可以将来自不同类的标志(int 值)混合在一起而无需任何编译器检查。

在同一本书(“Effective Java”)中,我看到了 EnumSet 的使用,但随后您的用户调用变为:

printText("hello", EnumSet.of(Style.Bold, Style.ITALIC));

我觉得这有点冗长,我更喜欢 SWT 的优雅。

还有其他选择吗?或者这基本上是您必须选择的两种口味?

【问题讨论】:

  • 我想你的意思是STYLE_ITALIC = 1 &lt;&lt; 1
  • @Victor 我认为这是位域方法常见问题的一个很好的证明!
  • 谢谢@VictorZamanian 我更新了问题
  • 你觉得第二个“冗长”的地方是什么?这是一个更长的字符。你觉得第一个“优雅”是什么?它所做的只是抛弃类型安全——这没有什么优雅的。

标签: java swt flags enumset


【解决方案1】:

猜你碰壁了。我没有看到任何其他选择。 Java 很冗长,这是事实。在这种情况下,我通常会添加一个局部变量以使代码更具可读性。你可以这样做,

EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.ITALIC);
printText("hello", styles);

【讨论】:

    【解决方案2】:

    如果您需要位样式标志,Java 会将它们包装在 BitSet 中。它已经存在了很长时间,但很少有人愿意使用它(更喜欢在 int 中嵌入 C 风格的位处理)。

    The api for BitSet can be found here.

    再加上一些精心挑选的静态整数,在您开始一次检查和设置多个位之前,它的表现非常好。

    【讨论】:

    • 是的,我在上学期的一门课程的期末考试中使用了 BitSet 作为标志。这是一个优雅的解决方案,没有其他学生使用过,我的教授非常喜欢它。 :) 我会鼓励人们更多地使用 BitSet,它似乎并没有被大量使用。
    【解决方案3】:

    我建议您使用EnumSet 方法。

    EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.Italic);
    

    这种方法提供了更好的类型安全性,Style 作为一个枚举将拥有成熟的 OO 功能。

    【讨论】:

      【解决方案4】:

      对于遇到此问题的任何人的迟到答案。这是一种减少内存并拥有像 api 一样好的枚举的方法:

      public static class MyFlag {
      
          public static final MyFlag A = new MyFlag(1<<0);
          public static final MyFlag B = new MyFlag(1<<1);
          public static final MyFlag C = new MyFlag(1<<2);
          public static final MyFlag ALL = A.and(B).and(C);
      
          private final int flag;
      
          private MyFlag(int flag){
              this.flag = flag;
          }
      
          public MyFlag and(MyFlag limit){
              return new MyFlag(flag & limit.flag);
          }
      
          public MyFlag not(MyFlag limit){
              return new MyFlag(flag | ~limit.flag);
          }
      
          public boolean isSet(MyFlag limit){
              if(limit ==null){
                  return false;
              }
              return (this.flag & limit.flag) != 0;
          }
      }
      

      方法:

      public void doFoo(MyFlag flag){
         if(MyFlag.A.isSet(flag)){
         ....
         }
         if(MyFlag.C.isSet(flag)){
         ....
         }
      }
      

      呼叫:

      x.doFoo(MyFlag.A.and(MyFlag.C));
      

      【讨论】:

      • 这究竟是如何减少内存的?
      • 通过仅使用一个 int 变量来存储多个标志(通过使用位掩码),而不是为每个标志使用单独的变量
      • 除了你现在在内存中有 n 个额外的对象(MyFlag 实例)
      【解决方案5】:

      如果您只有有限数量的方法将采用一组样式(如您的示例中的 printText),您可以调整它们的签名以采用可变数量的样式参数:

      void printText(String text, Style... flags) {
        EnumSet<Style> style = logicalOr(flags); // see comment below
        ...
       }
      

      然后你的调用非常接近无类型(int)标志路由:

      printText("hello", Style.BOLD, Style.ITALIC);
      

      遗憾的是,没有 EnumSet.of(E... ) 工厂,只有 EnumSet.of(E first, E... more),因此您需要一个通用的 logicalOr 方法将您的数组拆分为第一个 + 其余块。 留给读者作为练习 =).

      【讨论】:

        猜你喜欢
        • 2015-05-28
        • 2010-09-30
        • 2017-05-23
        • 1970-01-01
        • 2010-09-12
        • 2015-07-14
        • 2012-05-18
        • 1970-01-01
        • 2016-03-20
        相关资源
        最近更新 更多