我想在开发人员试图改变不可变对象(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对象)?似乎提出以下建议:
set() 方法不受支持,因为它覆盖了基类,因此这可能是一个不错的选择。元素。此外,我什至不确定我是否应该在这里抛出异常。我可以简单地不更改对象,也不提醒开发人员他们正在尝试更改不可变对象(immutable对象),但这似乎也很麻烦。在 ImmutableVector3.set(x,y,z) 中抛出异常的问题是 set 必须在 ImmutableVector3 和 vector 3。所以现在,即使 Vector3.set(x,y,z) 永远不会抛出异常,它也必须放在 try/catch block 中。
最佳答案
抛出异常通常是可行的方法,您应该使用 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/
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更