Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.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 不可变类型:公共最终字段与getter_Java_Immutability - Fatal编程技术网

Java 不可变类型:公共最终字段与getter

Java 不可变类型:公共最终字段与getter,java,immutability,Java,Immutability,我需要一个小容器类来存储一些应该是不可变的字符串。由于字符串本身是一种不可变的类型,我想到了类似的东西: public final class Immu { public final String foo; public final String bar; public Immu(final String foo, final String bar) { this.foo = foo; this.bar = bar; } } 许多人似乎完全反对使用公共字段

我需要一个小容器类来存储一些应该是不可变的字符串。由于字符串本身是一种不可变的类型,我想到了类似的东西:

public final class Immu
{
  public final String foo;
  public final String bar;

  public Immu(final String foo, final String bar)
  {
    this.foo = foo;
    this.bar = bar;
  }
}
许多人似乎完全反对使用公共字段,而是使用getter。在这种情况下,这只是一个样板,因为字符串本身是不可变的


在这一点上,我可能缺少其他想法?

问题在于统一访问原则。您以后可能需要修改
foo
,以便通过一种方法而不是固定的方法获得它,如果您公开了字段而不是getter,则需要破坏API。

我会做您认为最简单、最清晰的事情。如果您有一个数据值类,该类仅由数量有限的类使用。esp是一个包本地类。然后我将避免使用getter/setter,并使用包本地或公共字段


如果您有一个希望其他模块/开发人员使用的类,那么从长远来看,遵循getter/setter模型可能是更安全的方法。

不太清楚是否有人将通过API使用您的代码。
如果您以后需要验证输入,您也将错过验证输入的机会。

此答案将被排除:

为什么不呢

interface Immu { String getA() ; String getB ( ) }

Immu immu ( final String a , final String b )
{
       /* validation of a and b */
       return new Immu ( )
       {
              public String getA ( ) { return a ; }

              public String getB ( ) { return b ; }
       }
}

我在主项目中使用公共final字段(anti?)模式来处理类,这些类基本上是一个具有构造函数的不可变数据结构,如果需要,还可以使用equals()、hashCode()、toString()等绝对基础。(我避免使用“struct”一词,因为对它有各种不同的语言解释。)

我不会将这种方法带到其他人的代码库(工作、公共项目等),因为它可能与其他代码不一致,并且优先考虑的原则是在罗马或最不意外

也就是说,关于Daniel C.Sobral和aioobe的答案,我的态度是,如果类设计因为不可预见的发展而成为问题,那么IDE中的字段私有化和添加访问器只需30秒,修复损坏的引用不超过5到10分钟,除非有数百个。任何失败的结果都会得到它本来应该进行的单元测试。:-)


[编辑:高效Java非常坚决地反对这一观点,同时指出它对不可变字段的“危害较小”。

我发现这条线程希望得到一些实际的论点,但我在这里看到的答案对我没有多大帮助。经过更多的研究和思考,我认为必须考虑以下几点:

  • public final
    对于不可变类型来说看起来最干净
  • 可变类型可以由访问器更改,即使这不是预期的-在并发环境中,这可能会导致很多麻烦
  • 构造函数中不能有参数。如果您需要工厂方法(例如LMAX干扰器),这一点非常重要。以类似的方式,通过反射实例化对象变得更加复杂

  • 能手和二传手可能有副作用。使用
    public final
    可以清楚地告诉程序员,没有隐藏的魔法发生,对象本身就是哑的:)
  • 不能将包装器或派生类实例返回给访问器。同样,当字段被赋值时,您应该知道这一点。在我看来,容器类不应该关心返回给谁

如果您处于开发中期,没有任何指导方针阻止您,并且项目是孤立的,或者您可以控制所有涉及的项目,我建议对不可变类型使用
public final
。如果您决定以后需要getter,Eclipse提供了
Refactor
->
封装字段…
,它会自动创建这些字段并调整对该字段的所有引用。

忘记封装、不变性、优化和所有其他大字。如果您试图编写好的java代码,我建议您只使用getter,因为它对java友好,而且最重要的是,它可以节省大量时间在Google上搜索why

例如,您可能不希望在编写代码时使用流,但后来您发现

listOfImmus.stream().map(immu->imm.foo).collect(Collectors.toSet());//带场
listOfImmus.stream().map(Immu::getFoo.collect(Collectors.toSet());//带吸气剂
供应商s=()->immu.foo;//带场
供应商s=immu::foo;//带吸气剂
//最终字段即使不是不可能的,也很难模拟。
Mockito.when(immuMock.getFoo())。然后返回(“what ever”);
//有一天,您的代码被用于需要setter-getter的java bean中。。
¯\_(ツ)_/¯
这个列表可以是长的,也可以是短的,或者可能对您的用例没有任何意义。但是您必须花时间说服自己(或您的代码审阅者)为什么您可以或应该反抗java正统

最好只编写getter/setter,然后花时间做一些更有用的事情:比如抱怨java,使用public-final可能适合这么小的工作,但它不能作为一种标准实践

考虑下面的情况

Public class Portfolio {
   public final String[] stocks;
}
当然,由于是不可变的,这个对象被初始化为vis构造函数,然后直接访问。我必须告诉你其中的问题吗?很明显

考虑您的客户编写如下代码-

Portfolio portfolio = PortfolioManager.get(“Anand”);
Portfolio.stocks[0] = “FB”;
portfolio.calculate();
这可行吗?您的客户端库能够操纵对象的状态,或者更确切地说,能够在运行时表示中进行攻击。这是一个巨大的安全风险,当然像SONAR这样的工具会提前发现它。但只有在您使用getter setter时,它才是可管理的

如果您使用的是getter,那么您可以很好地编写

   Public class Portfolio {
      private final String[] stocks;
      public String[] getStocks() {
          return Arrays.coptOf(this.stocks);
      }
   }
这可以防止您受到潜在的安全威胁

看看上面的例子,如果您使用的是数组,那么强烈建议不要使用公共final