gpt4 book ai didi

java - 我应该对不可变类的突变尝试抛出异常吗?如果是这样,哪个异常(exception)?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:44:41 25 4
gpt4 key购买 nike

我想在开发人员试图改变不可变对象(immutable对象)时提醒他。不可变对象(immutable对象)实际上是可变对象的扩展,并覆盖了该对象上的 setter 以使其不可变。

可 rebase 类:Vector3

public class Vector3 {
public static final Vector3 Zero = new ImmutableVector3(0, 0, 0);

private float x;
private float y;
private float z;

public Vector3(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}

public void set(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}

不可变版本:ImmutableVector3

public final class ImmutableVector3 extends Vector3 {
public ImmutableVector3(float x, float y, float z) {
super(x, y, z);
}

//Made immutable by overriding any set functionality.
@Override
public void set(float x, float y, float z) {
throw new Exception("Immutable object."); //Should I even throw an exception?
}
}

我的用例如下:

public class MyObject {
//position is set to a flyweight instance of a zero filled vector.
//Since this is shared and static, I don't want it mutable.
private Vector3 position = Vector3.Zero;
}

假设我团队中的一名开发人员决定他需要操纵对象的位置,但目前它被设置为静态、不可变的 Vector3.Zero 共享 vector 实例。

如果位置 vector 设置为 Vector3.Zero 的共享实例,他最好提前知道他需要创建可变 vector 的新实例:

if (position == Vector3.Zero)
position = new Vector3(x, y, z);

但是,假设他没有先检查这个。我认为,在这种情况下,最好在 ImmutableVector3.set(x,y,z) 方法中抛出一个异常,如上所示。我想使用标准的 Java 异常,但我不确定哪个最合适,而且我也不是 100% 相信这是处理这个问题的最佳方法。

我在(这个问题)[IllegalStateException 是否适合不可变对象(immutable对象)?似乎提出以下建议:

  • IllegalStateException - 但它是一个不可变对象(immutable对象),因此只有一个状态
  • UnsupportedOperationException - set() 方法不受支持,因为它覆盖了基类,因此这可能是一个不错的选择。
  • NoSuchElementException - 我不确定这会是一个好的选择,除非该方法被视为一个 元素

此外,我什至不确定我是否应该在这里抛出异常。我可以简单地不更改对象,也不提醒开发人员他们正在尝试更改不可变对象(immutable对象),但这似乎也很麻烦。在 ImmutableVector3.set(x,y,z) 中抛出异常的问题是 set 必须在 ImmutableVector3 vector 3。所以现在,即使 Vector3.set(x,y,z) 永远不会抛出异常,它也必须放在 try/catch block 中。

问题
  • 除了抛出异常之外,我是否忽略了另一种选择?
  • 如果异常(exception)是最好的方式,我应该选择哪种异常(exception)?

最佳答案

抛出异常通常是可行的方法,您应该使用 UnsupportedOperationException .

Java API 本身确实在 collections framework 中推荐了这一点:

The "destructive" methods contained in this interface, that is, the methods that modify the collection on which they operate, are specified to throw UnsupportedOperationException if this collection does not support the operation.

另一种方法,如果您创建完整的类层次结构,则创建一个父类(super class) Vector,它不可修改且没有像 set()< 这样的修改方法,以及两个子类 ImmutableVector(保证不变性)和 MutableVector(可修改)。这会更好,因为你可以获得编译时安全性(你甚至不能尝试修改 ImmutableVector),但根据情况可能会过度设计(你可能最终会得到很多类).

例如,为 Scala collections 选择了这种方法。 , 它们都存在三种变体。

在您想要修改 vector 的所有情况下,您都使用类型 MutableVector。在您不关心修改而只想从中读取的所有情况下,您只需使用 Vector。在所有你想保证不变性的情况下(例如,一个 Vector 实例被传递到构造函数中,你想确保以后没有人会修改它)你使用 ImmutableVector (它通常会提供一个复制方法,因此您只需调用 ImmutableVector.copyOf(vector))。永远不需要从 Vector 进行向下转换,而是指定您需要的正确子类型作为类型。这个解决方案(需要更多代码)的全部要点是类型安全和编译时检查,因此向下转换破坏了这个好处。但是也有异常(exception),例如 ImmutableVector.copyOf() 方法作为优化通常看起来像这样:

public static ImmutableVector copyOf(Vector v) {
if (v instanceof ImmutableVector) {
return (ImmutableVector)v;
} else {
return new ImmutableVector(v);
}
}

这仍然是安全的,并且为您提供不可变类型的另一个好处,即避免不必要的复制。

Guava library拥有大量 immutable collection遵循这些模式的实现(尽管它们仍然扩展了可变的标准 Java 集合接口(interface),因此不提供编译时安全性)。您应该阅读它们的描述以了解有关不可变类型的更多信息。

第三种选择 是只使用不可变 vector 类,根本不使用可变类。出于性能原因使用的可变类通常是过早的优化,如 Java is very good in handling lots of small short-lived temporary objects (由于分代垃圾收集器,对象分配非常便宜,在最好的情况下对象清理甚至可以没有任何成本)。当然,对于像列表这样的非常大的对象,这不是解决方案,但对于 3 维 vector ,这肯定是一个选项(并且可能是最好的组合,因为它简单、安全,并且比其他方法需要更少的代码)。我不知道这个替代方案的 Java API 中的任何示例,因为在创建 API 的大部分部分的日子里,VM 没有那么优化,所以太多的对象可能是一个性能问题。但这不应该阻止您今天这样做。

关于java - 我应该对不可变类的突变尝试抛出异常吗?如果是这样,哪个异常(exception)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18517540/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com