- 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/10/20
投稿数: 205
投稿日時: 2007-04-04 15:36
あぶです。

【経緯】
最近、うちのプロジェクトにCheckStyleが導入され、
ウォーニング消しにあくせくで、手がつりそうです。。。

僕がどうこう言える立場ではないのですが、
特に気になるのは、変更しない変数にfinalを付けさせることです。
やたら多いので困っていますが、チェックから外す方針はないそうです。

そこで、思ったのですが、以下のように、

【本文】
引数にfinalを付けても、内容が変更されないことを保障できないじゃん。。。
ってことです。
コード:

void copy(final SampleClass src, SampleClass dst)
{
// src = dst; のようなのはコンパイルエラーになるが
// src.setAttribute1(dst.getAttribute1()); はコンパイルエラーにならない
}



C言語でも同じような問題があったような覚えがあるが、
どうやって対処したかは忘れました。。。

掲題のごとく、
引数で渡されたインスタンスの内容を変えないことを保障する
ことはできないのでしょうか?

【投票】
変更しない変数にはfinalを付けるべきでしょうか?

※タイトル変えました。すみません。

[ メッセージ編集済み 編集者: あぶぽん 編集日時 2007-04-04 16:24 ]
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-04 15:45
【投票】
最後の選択肢…絶対に付けるな! です。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-04 15:53
悩みましたが、望ましいに1票。

引数に代入したらどういう挙動になるだろう?という疑問は
初心者が悩む点のひとつですから、そこに対してコンパイルエラーで
事前にはじき出せるというメリットがあります。
そういう意味ではつけておいたほうが望ましいかな、と。

ただし、本題であるところのインスタンスの内容を変更されないように
という点に関してはなんら無力
であるので、そういう意味では
「関係がない」に投じるのが正しいのでしょうかね。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-04-04 16:04
引用:

あぶぽんさんの書き込み (2007-04-04 15:36) より:
【投票】
変更しない変数にはfinalを付けるべきでしょうか?


現在の Java の言語仕様であるかぎり、final は付けても意味がないと思います。付けることに手間と時間をかけるのは、手間と時間がもったいないから「付けないほうがいい」です。付けないとコンパイルエラーになるところ(インナークラス絡み等)にだけ、付けておけば良いと思います。

結局は、現在の Java の final は、変数に対する修飾なので、変数が指しているインスタンスがどうなろうと知ったことではないという仕様だからです。
これを補うために、setter をサブクラスにだけ付けて、引数の型をスーパークラスにしておくとか、immutable なラッパークラスに包むなど、いくつかのテクニックはあるかもしれませんが、コーディングの負荷が重すぎて、たかがそれだけのためにやるのは、逆にコードが見辛くなってしまい、やりたくはありません。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-04 16:13
nagiseさん、はじめまして。
投票ありがとうございます。

引用:

引数に代入したらどういう挙動になるだろう?という疑問は
初心者が悩む点のひとつですから、そこに対してコンパイルエラーで
事前にはじき出せるというメリットがあります。



プリミティブ型に関してはそうなんですよね。
参照型の場合は逆にまぎらわしくないですか?

String型の場合どうなんだろうと思って試してみました。
結果、以下のようになんと代入ができてしまいます。

コード:
void copy(final String src, String dst)
{
    // src = dst; これがエラーになりません
    // src = "ABC"; こちらもエラーになりません
}



下のほうは納得がいきます。
きっと別のインスタンスが生成されているのでしょうね。

引用:

ただし、本題であるところのインスタンスの内容を変更されないように
という点に関してはなんら無力
であるので、そういう意味では
「関係がない」に投じるのが正しいのでしょうかね。



「場合による」でしょうか? もしくは「どちらでもいい」でしょうか?
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-04 16:20
unibonさん、ありがとうございます。

【投票】項目訂正!

「絶対に付けるな!」を「コンパイルエラーが出ない限り、絶対に付けるな!!」
に変更します。

確かにエラーでるときありますね。。。

引用:

付けることに手間と時間をかけるのは、手間と時間がもったいないから
「付けないほうがいい」です。



手も時間もたっぷりとあるとしたら付けたほうがいいですか?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-04-04 16:29
引用:

あぶぽんさんの書き込み (2007-04-04 15:36) より:
掲題のごとく、
引数で渡されたインスタンスの内容を変えないことを保障する
ことはできないのでしょうか?


別の観点から言いますと、長年の経験から感じることですが、引数で渡されたインスタンスは、できるだけ get するだけにして、set はしないほうが良いです。
引数で渡されたインスタンスに対して set するのは、特別であり、javadoc にも目立つように書いておく、という風にしたほうが良いです。
たとえば、
引用:

あぶぽんさんの書き込み (2007-04-04 15:36) より:
コード:
void copy(final SampleClass src, SampleClass dst)
{
    // src = dst; のようなのはコンパイルエラーになるが
    // src.setAttribute1(dst.getAttribute1()); はコンパイルエラーにならない
}




の場合は、
コード:
static SampleClass copy(SampleClass src) {
    SampleClass dst = new SampleClass();
    dst.setAttribute1(src.getAttribute1());
    return dst;
}

void foo() {
    SampleClass a;
    SampleClass b = Hoge.copy(a);
}


などのような感じにします。(あくまでも例です。雰囲気だけのコードです。)

#元のコードだと、src と dst が逆のような。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-04-04 16:31
匿名クラスから参照したいときにfinalを付けますが、
後は意味がないので付けません。

変数のスコープを極力狭くするのは、Javaではセオリーになりますが、
匿名クラスを使うときにfinalな引数は全て参照可能になります。
ですので、むしろ全てfinalというのはアンチパターンのような気がします。
(コンパイル時にはどうなるか、覚えていません・・・)

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