Java 我应该在不可变类的变异尝试中引发异常吗?如果有,哪一个例外?
我希望在开发人员试图改变不可变对象时提醒他。不可变对象实际上是可变对象的扩展,它覆盖所述对象上的setter使其不可变 可变基类:Vector3Java 我应该在不可变类的变异尝试中引发异常吗?如果有,哪一个例外?,java,exception,immutability,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(
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;
}
}
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?
}
}
不可变版本:不可变向量3
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;
}
}
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共享向量实例
如果他提前知道如果位置向量设置为Vector3的共享实例,他需要创建可变向量的新实例,这将是最好的。零:
if (position == Vector3.Zero)
position = new Vector3(x, y, z);
但是,假设他没有先检查这个。我认为,在这种情况下,最好抛出一个异常,如上面的ImmutableVector3.set(x,y,z)
方法中所示。我想使用一个标准的Java异常,但我不确定哪一个最合适,我也不是100%确信这是处理这个问题的最佳方法
我在(这个问题)上看到的建议[非法状态例外适用于不可变对象吗?似乎建议如下:
- IllegalStateException——但它是一个不可变的对象,因此只有一个状态
- UnsupportedOperationException-不支持
方法,因为它重写基类,因此这可能是一个不错的选择set()
- NoTouchElementException-我不确定这是一个好的选择,除非该方法被视为
元素
ImmutableVector3.set(x,y,z)中抛出异常的问题
是指set
必须在ImmutableVector3
和Vector3
上引发异常。因此,现在,即使Vector3.set(x,y,z)
永远不会引发异常,它也必须被放置在try/catch
块中
问题
- 除了抛出异常,我是否忽略了另一个选项
- 如果例外是最好的方式,我应该选择哪种例外
- 抛出异常通常是一种方法,您应该使用
Java API本身确实在以下方面提出了建议:
此接口中包含的“破坏性”方法,即修改其操作的集合的方法,指定在该集合不支持该操作时引发UnsupportedOperationException
如果创建完整的类层次结构,另一种方法是创建一个超类
向量
,该超类不可修改,没有像set()
这样的修改方法,以及两个子类不可变向量
(保证不可变)和可变向量
(可修改)。这会更好,因为您获得了编译时安全性(您甚至无法尝试修改ImmutableVector
),但根据具体情况,可能会过度设计(最终可能会产生许多类)
例如,选择这种方法是因为,它们都存在三种变体
在所有需要修改向量的情况下,都使用类型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);
}
}
这仍然是安全的,并且为您提供了不可变类型的另一个好处,即避免了不必要的复制
有大量遵循这些模式的实现(尽管它们仍然扩展了可变标准Java集合接口,因此不提供编译时安全性)。您应该阅读它们的描述,以了解有关不可变类型的更多信息
第三种选择是只使用不可变向量类,而不使用可变类。通常出于性能原因使用可变类是一种过早的优化,如(由于采用了分代垃圾收集器,对象分配非常便宜,而且在最好的情况下,对象清理甚至可以不花费任何成本)。当然,对于非常大的对象(如列表),这不是解决方案,但对于三维向量,这肯定是一个选项(可能是最好的组合,因为它简单、安全,并且比其他组合需要更少的代码)。我不知道Java API中有任何这种替代方法的例子,因为在创建API的大部分部分时,VM没有得到优化,太多的对象可能是一个性能问题。但这不应该阻止您今天这样做。如果您尝试变异不可变的cl,您应该抛出一个编译器错误屁股
不可变类不应该扩展可变类。鉴于您的情况,我认为您应该抛出一个
不支持操作异常
package com.sandbox;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Sandbox {
public static void main(String[] args) throws IOException {
List<Object> objects = Collections.unmodifiableList(new ArrayList<Object>());
objects.add(new Object());
}
}
package.com.sandbox;
导入java.io.IOException;
导入java.util.ArrayList;
导入java.util