- PR -

変更しない変数にfinalを付けるべきですか?

投票結果総投票数:69
必須 2 2.90%
望ましい 25 36.23%
場合による 7 10.14%
どっちでもいい 1 1.45%
付けなくていい 28 40.58%
付けないほうがいい 4 5.80%
付けるな 0 0.00%
絶対に付け 2 2.90%
  • 投票は恣意的に行われます。統計的な調査と異なり、投票データの正確性や標本の代表性は保証されません。
  • 投票結果の正当性や公平性について、@ITは一切保証も関与もいたしません。
投稿者投稿内容
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-04-05 16:46
引用:

あぶぽんさんの書き込み (2007-04-05 15:35) より:
C++ではどのような点が問題になっているのでしょう?



引用:

この方向性だと、メソッド毎にmutable/immutableを定義しないと
使い物にならなくなるので、C++のconst関数と同じになってしまうのでは?


まさにこの辺です。

C++では、

・const修飾された実体/参照からはconst修飾されたメンバ関数のみを呼び出せる
・const修飾されたメンバ関数内では全メンバ変数がconst修飾されたように扱われる

この仕様から、表面上は参照であろうとも内部まで不変な扱いが可能なわけです。

ただし、constメンバ関数内のメンバ変数のconst修飾を覆すためのmutableという
修飾子があったり、変数のconst修飾はキャストで取り除くことが可能なため、
実質的な保証にはなりません(無理矢理いじれるということです)。

例えば、C++の文字列クラスではconstなメンバ関数が大量に並んでいますが、
結局は複雑化しただけで扱いにくいものになっていると思っています。

その点、JavaではStringとStringBuffer/StringBuilderに分割され、
前者はimmutable、後者はmutableとすることでシンプルに解決しています。

Javaにはconstが予約語として残っているなど、苦心の跡が見えますが、
今のところfinal以外には有効的な解決策は実装されていません。

Objectにfreeze()のようなメソッドを導入して、オブジェクトを不変化
できるようにするのも解決策のひとつでしょうけど、個々のインスタンスに
不変フラグを追加し、インスタンス変数の更新毎に不変フラグを検査しないと
いけなくなってしまうため、それなりな規模のVM仕様の変更になってしまいます。

なので、Stringのようなimmutableクラスであることを明示するために、
クラス全体をimmutable修飾し、クラスの設計者側が意図をアピールできる
程度になってしまうのではないかな、と思っています。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-04-05 16:50
私も蒸し返して申し訳ないですが、
完璧なのは状態の変更可能なインターフェイスを
外部に公開しないということでしょう。

状態の変更可能なインターフェイスを公開する場合、
デコレータパターンなどで、例外をスローするようなラッパーを作って渡すという方法もあります。

コード:
class Hoge{

    private String hoge;

	String getHoge(){
		return hoge;
	}

	void setHoge(String hoge){
		this.hoge = hoge;
	}
}

class ReadOnlyHoge extends Hoge{

	private Hoge hoge;

	ReadOnlyHoge(Hoge hoge){
		this.hoge = hoge;
	}

	String getHoge(){
		return hoge.getHoge();
	}

	void setHoge(String hoge){
		throw new UnsupportedOperationException();
	}
}

class Test{

	public static void main(String[] args){
		Hoge hoge = new Hoge();
		hoge.setHoge("test");
		other(new ReadOnlyHoge(hoge));
	}

	public static void other(Hoge hoge){
		hoge.getHoge();
		hoge.setHoge("test2");
	}
}

小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2007-04-05 16:56
引用:


# CheckStyleの(いや、うちの規約の)せいです。。。蒸し返してすみません。




その規約が、参照するインスタンスの内容を変えない為の規約では無く、
参照変数自体の上書きによる、誤ったデータ参照や判定をさせないための
規約ということですよね。
コード:
Punyu getPunyu(Fuwa fuwa)
{
    final Punyu p = new Punyu();
               .
               .
               .
    fuwa = new Fuwa();
    p.setValue(funa.getValue());


    return p;
}



これ以上の効果を、final修飾子だけに期待するのは間違いということで、
使う側に注意を要するおまじないになっているのが、finalの残念なところ
ですよね。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-05 17:09
引用:

かつのりさんの書き込み (2007-04-05 16:50) より:
状態の変更可能なインターフェイスを公開する場合、
デコレータパターンなどで、例外をスローするようなラッパーを作って渡すという方法もあります。



思い出しました。
java.util.Collections.unmodifiableCollection()
などがその例ですね。
現実解としてはこっちですねぇ。
# 空回りしてますね。自分 orz
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-05 17:16
小僧さん、

もう、頭がプニュプニュのフワフワになってしまいそうです

finalでもなんでもいいからインスタンスを不変にさせてください。。。

ちょっと、OpenJDKコミュニティーに働きかけてみようかな。。。
小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2007-04-05 17:20
A.デコレータパターンでクラスを覆って、内部状態を変更していしまうメソッドをオーバーライドしたコードから、UnsupportedOperationException をスローする

B.内部状態を変更するメソッド群(a)としないメソッド群(b)を、
別々のインターフェースとして定義。
内部状態が不変なインスタンスとして扱いたい場合は、bインターフェースだけを
使う。

やはりこの辺ですかね。
もっとラクしたいなー!!



あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-05 17:20
あしゅさん、

C++の仕様、思い出してきました。

キャストではずせるのはプリミティブ型でも同じだったような気が。。。

やはり、開発者の良識に任せる。。。ですか。
小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2007-04-05 17:24
引用:

あぶぽんさんの書き込み (2007-04-05 17:16) より:
小僧さん、

もう、頭がプニュプニュのフワフワになってしまいそうです

finalでもなんでもいいからインスタンスを不変にさせてください。。。

ちょっと、OpenJDKコミュニティーに働きかけてみようかな。。。



俺もプニュプニュですわ!

スキルアップ/キャリアアップ(JOB@IT)