cru*_*ush 7 java exception immutability
我希望在他试图改变不可变对象时提醒开发人员.不可变对象实际上是可变对象的扩展,并覆盖所述对象上的setter以使其不可变.
可变基类: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;
}
}
Run Code Online (Sandbox Code Playgroud)
不可变版本: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?
}
}
Run Code Online (Sandbox Code Playgroud)
我的用例如下:
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;
}
Run Code Online (Sandbox Code Playgroud)
假设我的团队中的开发人员决定他需要操纵对象的位置,但是目前它被设置为静态的,不可变的Vector3.Zero共享向量实例.
如果他提前知道他需要创建一个可变向量的新实例,如果位置向量设置为Vector3.Zero的共享实例,那将是最好的:
if (position == Vector3.Zero)
position = new Vector3(x, y, z);
Run Code Online (Sandbox Code Playgroud)
但是,让我们说他不会先检查这个.我认为,在这种情况下,抛出如上所示的ImmutableVector3.set(x,y,z)方法中的异常会很好.我想使用标准的Java异常,但我不确定哪个最合适,我不是100%确信这是处理这个问题的最佳方法.
我见过的建议(这个问题)[IllegalStateException是否适用于不可变对象?似乎建议如下:
set()方法不受支持,因为它覆盖了基类,因此这可能是一个不错的选择.element.此外,我甚至不确定我应该在这里抛出异常.我可以简单地不更改对象,也不会提醒开发人员他们正在尝试更改不可变对象,但这似乎也很麻烦.在抛出异常的问题ImmutableVector3.set(x,y,z)是,set有扔在两者的异常ImmutableVector3和Vector3.所以现在,即使Vector3.set(x,y,z)永远不会抛出异常,它也必须放在一个try/catch块中.
Phi*_*ler 10
抛出异常通常是要走的路,你应该使用UnsupportedOperationException.
Java API本身确实在集合框架中推荐这个:
如果此集合不支持该操作,则指定此接口中包含的"破坏性"方法(即修改其操作集合的方法)将抛出UnsupportedOperationException.
如果创建完整的类层次结构,另一种方法是创建一个Vector不可修改的超类,并且没有修改方法,如set()两个子类ImmutableVector(保证不变性)和MutableVector(可修改).这样会更好,因为你获得了编译时的安全性(你甚至无法尝试修改ImmutableVector),但是根据情况可能会过度设计(最终可能会有很多类).
例如,这种方法是为Scala集合选择的,它们都存在三种变体.
在要修改矢量的所有情况下,都使用该类型MutableVector.在您不关心修改并且只想阅读它的所有情况下,您只需使用Vector.在你想要保证不变性的所有情况下(例如,一个Vector实例被传递给构造函数,并且你想确保以后没有人会修改它)你使用ImmutableVector(通常会提供一个复制方法,所以你只需要调用ImmutableVector.copyOf(vector)).从Vector不需要向下转换,请指定您需要的正确子类型.这个解决方案的全部要点(需要更多代码)是关于类型安全和编译时检查,所以向下销售会破坏这种好处.但也有例外,例如ImmutableVector.copyOf(),作为优化,该方法通常如下所示:
public static ImmutableVector copyOf(Vector v) {
if (v instanceof ImmutableVector) {
return (ImmutableVector)v;
} else {
return new ImmutableVector(v);
}
}
Run Code Online (Sandbox Code Playgroud)
这仍然是安全的,并为您提供了不可变类型的另一个好处,即避免不必要的复制.
该番石榴库收集了大量的不可变集合遵循这些模式(当然,它们还扩展了可变标准的Java集合接口,从而提供任何编译时安全性)的实现.您应该阅读它们的描述以了解有关不可变类型的更多信息.
第三种选择是只使用不可变的vector类,而根本没有可变类.出于性能原因而使用的可变类通常是过早优化,因为Java非常善于处理大量短暂的临时对象(由于分代垃圾收集器,对象分配非常便宜,并且对象清理甚至可以没有任何成本最好的情况下).当然,对于像列表这样的非常大的对象来说,这不是解决方案,但对于三维向量,这肯定是一种选择(可能是最好的组合,因为它简单,安全,并且需要的代码少于其他代码).我不知道此替代方案的Java API中的任何示例,因为在创建API的大多数部分的时代,VM并未进行优化,因此太多对象可能是性能问题.但这不应该阻止你今天这样做.
| 归档时间: |
|
| 查看次数: |
1994 次 |
| 最近记录: |