ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

JavaコミュのList list = new ArrayList();

  • mixiチェック
  • このエントリーをはてなブックマークに追加
List list = new ArrayList();

タイトルはあえてコードだけにしてみました。

大きなテーマとしては
「List list = new ArrayList();」
と記述することのメリットを考える、です。
下記のコードのαとβを比較したメリットでもかまいません。

α:ArrayList list = new ArrayList();
β:List list = new ArrayList();
γ:List list = new Vector();
δ:Vector list = new Vector();
※あとで必要になるかもしれないため、γとδも書いておきました。

これをいくつかの視点から分けて考えます。
視点についてはあらゆる視点をすべて同時に議論をしようとすると
混乱するので、期間で区切って一つ一つ議論していきたいです。
最初は(1)だけ、(1)が終わるまで他の視点は考えないというルールでお願いします。

●視点
(1):オブジェクト指向らしさ
(2):メンテナンス性の高さの観点からよりよいコードか
(3):Javaらしさ
(4):その他の観点から

●ケース
A:メソッドの内部でしか使わない場合
B:メソッドの戻り値になっている場合
C:マルチスレッド下で使用されることが無いことが確定しているケース
D:マルチスレッド下で使用されるかどうか分からないケース


◎注意
ケースは、同時進行でOKとします。
視点やケースは必要ならば追加してください。
具体的で論理的で理性的で紳士的な書込みをお願いします。

よろしくお願いします。

コメント(249)

200 みうラスさん


わかりました。ありがとうございます。
208
> 後者もコンパイルが通るように修正しても実行時障害が発生するのではないかという認識です。

後者でバグを発生させるのはどんなパターンでも不可能ですよ。
具体的に考えましたか?初心者には難しいかもしれませんね。
実は非常に簡単な話なのですが。
わからない人のために具体的に書いてみましょうか。

修正前A
# List list = new ArrayList();
# list = new ArrayList();

修正後A1:OK
# List list = new CopyOnWriteArrayList();
# list = new CopyOnWriteArrayList();

修正後A2:バグ
# List list = new CopyOnWriteArrayList();
# list = new ArrayList();

修正後A3:バグ
# List list = new ArrayList();
# list = new CopyOnWriteArrayList();


修正前B
# ArrayList list = new ArrayList();
# list = new ArrayList();

修正後B1:OK
# CopyOnWriteArrayList list = new CopyOnWriteArrayList();
# list = new CopyOnWriteArrayList();

修正後B2:コンパイルエラー
# CopyOnWriteArrayList list = new ArrayList();
# list = new ArrayList();

修正後B3:コンパイルエラー
# ArrayList list = new CopyOnWriteArrayList();
# list = new ArrayList();

修正後B4:コンパイルエラー
# ArrayList list = new ArrayList();
# list = new CopyOnWriteArrayList();

修正後B5:コンパイルエラー
# ArrayList list = new CopyOnWriteArrayList();
# list = new CopyOnWriteArrayList();

はじめに変数1にArrayListを使用していた場合、
修正漏れで実行時例外を発生させることは不可能なのですよ。
理解できましたか?
>197
>> それをArrayListが登場するたびに考えなくてはいけないの?
>> 普通そこまでしないでしょ
>> もう少し自分のコードを読む人のことを考えた方がいいんじゃない?
>考えないんですか?
>必要とする型がしっかり定義してあるほうが、読むほうは簡単だと思いますが。

えー?
Listの下位クラスが登場するたびにいちいち非機能要件を考えるってこと?
そんなこと普通しないよ

抽象化とかもうちょっと勉強しようよ
>197
>インタフェースさえ適合すれば、全部Listにすべきと書いてあるように見えますが。

左辺と右辺を全てArrayListでといっているのは自分じゃん
左辺がListだとだめな理由が馬鹿げてるっていってるんだけど

全てのPGにいちいちListの非機能要件を考慮することを強要する気?
214
>CopyOnWriteArrayListを使うこと自体がバグならば

その認識が間違っているのですけどね。
ArrayListを使うことがバグで
CopyOnWriteArrayListを使うようにすれば問題はなくなるという話です。

やっぱり初心者の方には難しかったのかもしれませんね。
きちんと説明はしていませんでしたが、

# 1. List で宣言する場面
# 2. ArrayList で宣言する場面
# 3. Collection で宣言する場面
# 4. Object で宣言する場面
# の境界線が私は知りたいです.

今はこの話の方向に向かって話を進めているつもりです。
しかし、上記の分類の境界を探すという視点で考えてしまうと
網羅性が低下してしまうと思っているため、
出来るだけMECEに考える為に「A, B-1, B-2, C」
というケースに分けて考えようということで話を進めています。
ぶっちゃけCは当たり前の話なので議論にならず瞬殺だと思います。
一方で一番議論が分かれるのがAだと思います。

簡単なほうから順にやったほうがよかったかも知れませんが…。


209 もかまたりさん
>私の投稿にあるような右辺の交換をして「文脈が成り立つ」例は殆どないでしょう。

これがAに限定した話だったら少ないと思います。
しかしCの話だったら多いですよ。


※ケースの記述を再掲しておきます
●ケース
A:メソッドの内部でしか使わない場合
B-1:メソッドの戻り値の定義
B-2:メソッドの戻り値を受け取る場合
 (あえて具象クラスで返すメソッドを受ける変数か?)
C:メソッドの引数の定義
> 213
> 全てのPGにいちいちListの非機能要件を考慮することを強要する気?
当然強要しますよ?
うちでは強要できないようなPGは必要としませんし、出来るように教育します。

強要しないにしても、「型をArrayListにすることが非機能用件を考慮する」という意味が分かりません。
型をList型にしたところで、考慮しないでどうやってArrayListを選択してnewするの?

なんにしろ、chunさんと私では前提が違いすぎです。
あなたの環境とは違う環境があるということも理解してください。
あなたのやり方は私の環境では使えませんし、逆もまたそうでしょう。

下らないので、これ以上はやめておきます。
>218
>> 全てのPGにいちいちListの非機能要件を考慮することを強要する気?
>当然強要しますよ?
>うちでは強要できないようなPGは必要としませんし、出来るように教育します。

へぇ
最初から非機能機能まで強要するんですか
すごい教育方針ですね
それがちゃんとできてるとはとても思えないけど(笑

>なんにしろ、chunさんと私では前提が違いすぎです。
>あなたの環境とは違う環境があるということも理解してください。
>あなたのやり方は私の環境では使えませんし、逆もまたそうでしょう。

環境のせいにしないでください
あなたは自分でもこう言っているんですよ

>ただ、内部実装を意識しないで自らListをNewするというケースが、私の中では殆ど思い浮かばないのです。

環境じゃなくて単に理解できないだけなんですよね

よほど稀な状況でない限り左辺をListにすることでデメリットが発生することはありません(あなたがその状況に居るとはとても思えませんし、仮にそうだとしてもあなたの発言は自分の状況がレアケースであることを理解しているものではありません、つまりメチャクチャです)
逆に左辺をArrayListにすることで発生するデメリットは在ります
そのデメリットはこのトピでも出てきているしEffectiveJavaにも記述されています
ですから左辺Listにすべしなのです

私があなたにもっと勉強した方がいいんじゃないの?といったのは、散々EffectieJavaをよんだほうがいいと皆がコメントしているのに、それを無視して自分勝手な意見ばかりを言っていることに対してです
>>192 で再度のケース分けが示されていますが, 視点は >>0 のままで引き続き「(1) オブジェクト思考らしさ」についてなんですかね?
個人的に思うのは, 視点ではなくまずケースで分けて, それに対して色々な視点で語った方が自然だと思います. 色々考えていると視点からはみ出すことが度々あるので.

ケース A に関しては「どっちでもいいんじゃない?」という意見です. 特筆すべきメリットもデメリットも感じないし.
例えば "LinkedList list = new LinkedList()" と書いてあれば, 「あぁ, きっと LinkedList じゃなきゃいけないロジックがあるんだろうな」と思って読み進むので, ケース A の書き分けに関してはどちらかと言うと「可読性」の問題かなぁ, と思います.


> 187: じゃまさん
> また、ここで行われている議論の中では「どんなケースでもListで受けるべき」と書いてあるように解釈しているので、こういう書き方をしています。

>>170 読んでくれてないんですね. 残念です.

それと >>218, >>219 で「非機能要件」の意味が食い違っている予感がする. 単なる予感ですが.

> 215: みうラスさん
> やっぱり初心者の方には難しかったのかもしれませんね。

こんな発言するから抉れるんであって……
> 219, 220
失礼、これ以上はトピックを汚すのでMsgでやります。
メッセージがきたので、さらしまーす

****************************
じゃまwrote

> 最初から非機能機能まで強要するんですか
> すごい教育方針ですね
> それがちゃんとできてるとはとても思えないけど(笑
これ、こっちでは当たり前です。
強要した上でもちろんサポートする。
PGというかコーダーとしか見ていないあなたのところでは無いでしょうけど。
自分のとこで出来ないからといって、他人のところで出来ないわけじゃないですよ。

>>ただ、内部実装を意識しないで自らListをNewするというケースが、私の中では殆ど思い浮かばないのです。
> 環境じゃなくて単に理解できないだけなんですよね
手前にも書きましたけど、じゃあどうやって"List list = new ArrayList"って書くときに、ArrayListを決定してるんですか?
ArrayListがほしいからそうしてるんじゃないんですか?
それは誰が決定するのですか?new ArrayListって書く人が上級PGで、その先を書くのがコーダーなんですか??それともコーダーはArrayListなんて使うなってことですか???

> よほど稀な状況でない限り左辺をListにすることでデメリットが発生することはありません
そう、それは私もそう思います。ただ、万が一発生したときのデメリットが非常に大きいと考えているので、そう言っているのです。

> 私があなたにもっと勉強した方がいいんじゃないの
残念ながら、Effective Javaは読んでますし、そこに書いてあるメリット自体は分かります。
読んだのは一版ですが、8割くらいはその通り、その他はどうかってとこですね。
ただ、自分の経験や考え、状況から、メリット・デメリットを勘案してそう書いています。

私はEffectiv Javaに書いてあるから正しい、という考えはさらさらないので。
「学びて思わざれば則ち罔し」て言葉知ってますよね?
Effective Javaとか、デザインパターンとかばかり言う人は、この言葉を理解して無いんじゃないかとしか思えません。
> 223
え?どっちもどっちじゃない?
スレ主自体、荒らしてるし。
とっくにこのトピは無法地帯化してますよ(笑)
220 杵搗き餅さん
>>>192 で再度のケース分けが示されていますが, 視点は >>0 のままで引き続き
>「(1) オブジェクト思考らしさ」についてなんですかね?

すみません。説明が足りなかったようですね。
視点は無視でかまいません。ケースごとに考え、メリット・デメリットが
思いついた視点なんでもいいので挙げるという方向でお願いします。

>個人的に思うのは, 視点ではなくまずケースで分けて,
>それに対して色々な視点で語った方が自然だと思います.
>色々考えていると視点からはみ出すことが度々あるので.

なのでまさにおっしゃるとおりのルールです。
正直、自分が一番悩んでいる部分はケースAでした。
プロジェクトではListと書いているケースが圧倒的に多い。
しかし、考えるとそう書く必然性が思いつかない。
ので、Listと書く根拠が見つからないかなと思って投げかけてみたのですが

メリットもデメリットも強い根拠は挙がりませんでした。
※ケースAに限定した、そしてこのトピの書き込みに限定しての話ですが。
今まで挙がったメリットとデメリットをまとめておきます。

◎メリット
・クラスを変更する際に修正にかかる文字数が少なくてすむ
・初学者に対し「こんな書き方が出来るんだよ」と示すことが出来る
・プロジェクトの都合で記述を統一したいときに「とりあえずListと書いとけ」
 というルールにすると単純で守られやすい

◎デメリット
・勝手に変えられると困るときでも、交換自由かのように見える
・変数の宣言とオブジェクトの生成箇所が離れているときもしくは
 複数の箇所でオブジェクトの生成をしている場合で、かつ
 クラスの変更を行なう際に、修正し漏れが発生しうる

◎その他
・「Effective Java」に「Listと書け」っぽい事が書いてある
 ※いつでもそれでいいとは書いていない

こんなもんでしょうか?


「他にもあるよー」という方は追加してください。
おおむねまとまったら、ケースBを飛ばして、ケースCに行きたいと思います。
>227 みうラスさん

やっと、ひとしきり追えたので、書いてなさそうな内容の部分を...

一部にありましたけが、「抽象度を高める〜」的な意見ですが、
具象クラスが継承しているインタフェースで、
直接継承している(最も抽象度の"低い"インタフェース)の中からを選択することが私自身多いです。

もともと私は「プログラマの事情でしかない」と断じていますが、
そのプログラマの事情として(オブジェクト指向とは別個に)、
上記例だとListを継承するということはCollectionとIterableを継承していることを
暗黙的に伝えることと同じケースだと言えますよね?(メリット)

これって、オブジェクト指向がどうこうって言う話ではないですが、コレクションフレームワークを利用しますよ〜っていう宣言に近いのかなと。
その後コレクションフレームワークを意識しないプログラミングになっていると不思議な気持ちになりますし。(デメリット)

ArrayList自体は他にRandomAccess, Cloneable, Serializableの各種インタフェースを直接継承していますが、これらのインタフェースは、Listに比べて大分異なる意味を持ちあまり利用されないと思うので割愛します。
> 222
正直それほど低レベルな人とは思ってなかったですよ。
残念です。
もうちょっと自分の脳みそ使ってくださいね。

> 224,225
すいません。
>227 みうラスさん

それではメリットに2つ追加を。

 1. リファクタリング(メソッド抽出)の容易さについて
 2. 実装クラス切り替え時の保証について


まず1…の前に#203で挙げられたArrayListを使うメリットについて。

これは内部でArrayList型変数を使う一つの確かなメリットだと思います。
ですがこの場合、メソッド自体の作りが悪い(モジュール分割がうまく出来ていない)
可能性が高いです。
きちんとモジュール分割していれば、そのようなメソッド内部で
複数の生成箇所を修正し忘れる事は起こりにくいでしょう。
また、通常はArrayListのようなデータ構造を表現するオブジェクトは
一貫して何らかの意味を持つはずです。
それに対する生成処理が複数個所で行われるのなら、
生成処理部分をメソッドに切り出せば良いのではないでしょうか。
(もちろん、モジュール分割をしない(できない)方はざらにいるので、メリットには違いないと思います)

上記のようなコードに対するモジュール分割も含みますが、
そうでなくてもリファクタリングはあらゆる箇所で当たり前のように行います(よね?)
ArrayList型変数を使用している場合、メソッド抽出によって作成されたメソッドの引数・戻り値に
ArrayList型が入り込んでしまう可能性があります。
仮にクラス内までならArrayList型変数を許容したとしましょう。
今度は、抽出したメソッドをユーティリティクラスに移して、
別クラスでも使用したいという可能性もあります。
それでもArrayList型のまま…にはしませんよね。
List型であれば何の問題もなくリファクタリングを進めることが出来ます。
これはList型変数を使うメリットでもあり、
ArrayList型変数を使うデメリットにもなるのではないでしょうか。


次に2.についてですが、
Effective Java(第2版) 項目52をよく読んでみると、こんなことが書いてありました。

>インタフェースで宣言することで、インタフェースにないメソッドを誤って使用するのを防いでくれる
>その結果、周りのコードを変更することなく同じインターフェースの他の実装に置き換えることを可能にする

ArrayList型を使ってコーディングしていると、
誤ってArrayList独自のメソッドを使用する可能性があります。
List型を使ってコーディングすればそれが防げるわけですね。
そしてList型であれば、生成部分以降のコードの事を何も考えずに、
実装クラスを書き換えることができます。
ArrayList型だと独自メソッドを使用していないか確認する必要がありますね。
List・ArrayListだと対したことではないように感じるかもしれませんが、
別のインターフェース・実装クラスも踏まえて考えて頂きたいです。

Effective Javaがすべて正しいと主張するようにとれる書き込みが続いてしまったために、
Effective Javaの印象が悪くなっているように感じますが…
より良いプログラミングへのヒントになることは間違いありませんので、
是非読んでみて欲しいです。
ちなみに、「Effective Javaの記述についての理解」はもちもちさんが正しいと思われます。


あと、ちょっと気になったのですが、
List型変数を使うことにそんなに違和感を感じるものですか??
両者の抽象性・具体性もほぼ同じで、コードレベルでも概念レベルでも、
扱いに違いを感じません…。
実際、外面(公開メソッド)は何も変わらないですし、違いは内部動作(パフォーマンス)だけですね。
Collectionだと「データの集まり」的な表現なので、例えCollection型で事足りたとしても
さすがに「リスト」の代替として使うのは不自然に感じちゃいますね…。
ん〜やっぱり適切な抽象度が一番良いか。
228 mmikeさん
227のまとめはCollection・List・ArrayList(もしくは他の具象クラス)の
三者を比較した上で、Listと宣言することのメリットとデメリットです。
明示的には書いておらず、暗黙的になっていますけど。


つまり、以下のような事柄を挙げています。
・Collectionと宣言するよりも優れている理由
or (and)
・ArrayListと宣言するよりも優れている理由

・Collectionと宣言すれば発生しない問題
or
・ArrayListと宣言すれば発生しない問題


# CollectionとIterableを継承していることを暗黙的に伝えることと同じ

これは、Collection・List・ArrayList(もしくは他の具象クラス)の
どれにも当てはまることだと思います。よって三者を比較しての
メリットとは関係ないのではないでしょうか?

後者のデメリットについても同じ事を感じます。
Objectもしくは、Cloneable, Serializable等との比較をしていますか?

少しずれているように感じるので、228の記述は追加しないでおきます。
231 長老 さん

# 1. リファクタリング(メソッド抽出)の容易さについて

# まず1…の前に#203で挙げられたArrayListを使うメリットについて。
# これは内部でArrayList型変数を使う一つの確かなメリットだと思います。
# ですがこの場合、メソッド自体の作りが悪い可能性が高いです。

私もそう思います。何かが間違っていると思います…。
ただ、そういう状況が存在しない事を前提として考えてしまうのではなく、
そういうコードを書いてしまう人もいるという前提で捉えています。
私がひとりで考えているだけなら例として挙げなかったと思います。
しかし、193で青い鴉さんが挙げられたので「そういうふうに書人もいるんだな」
と思い、例として採用しました。ちなみにその時の内容は
「Listとして記述した方がいいケース」でしたが。


# ArrayList型変数を使用している場合、メソッド抽出によって
# 作成されたメソッドの引数・戻り値に
# ArrayList型が入り込んでしまう可能性があります。

これはつまり、eclipseなどの機能でメソッド抽出を行う際に
引数や戻り値の型を自動抽出されたコードのまま、何も手を加えず
何も考えずに使用してしまう、うっかりSEがいるという前提でしょうかね。

簡単に言い換えれば、
うっかりSEのリファクタリング作業を容易にするため、ってことでしょうか。
その場合、確かにListを使うメリットと言う事はできると思います。

しかし、メソッドの抽出を含めリファクタリングそのものは
細心の注意を払い行うべき作業だと思います。なので、
うっかりSEにリファクタリング作業を任せること自体が問題だと思いますし、
うっかりSEの負担軽減に注目することはややずれていると思います。

ましてやユーティリティクラス・メソッドの作成をうっかりSEに任せ、かつ
その後誰もレビューもしないということはあってはならないことだと思います。

なので、1は相当イレギュラーな例だと判断し、対象外とさせていただきます。
231 長老 さん

# 2. 実装クラス切り替え時の保証について

>ArrayList型を使ってコーディングしていると、
>誤ってArrayList独自のメソッドを使用する可能性があります。
>List型を使ってコーディングすればそれが防げるわけですね。

ArrayListで独自に拡張されているのは以下のメソッドです(たぶん)。
ensureCapacity, removeRange, trimToSize
このメソッドで提供されている機能を使用したいときが前提なのですよね。
で、この機能を使用したければ、ArrayListのメソッドを使わずに
Collectionsもしくは自分で独自に処理しろということなのですよね…。

そこはメリットでもデメリットでもあると思います。
・独自メソッドを使用してしまうかもしれず、
 独自メソッドを使用してしまった場合、他の実装クラスに交換しにくくなる
・独自メソッドを使用できず、他の何らかの方法で代用しなければならない

言うまでもないことですが、メリットだけにしか目を向けないのではなく、
メリット・デメリットの両面を考えるべきだと思います。
よって、上記の特徴はメリット・デメリットにそれぞれ加えます。


# あと、ちょっと気になったのですが、
# List型変数を使うことにそんなに違和感を感じるものですか??
# 両者の抽象性・具体性もほぼ同じで、コードレベルでも概念レベルでも、
# 扱いに違いを感じません…。
# 実際、外面(公開メソッド)は何も変わらないですし、違いは内部動作(パフォーマンス)だけですね。

私が知りたいのはListと書く事の妥当性です。もしくはそう記述する根拠です。
「実装クラスの交換が容易」という理由を上げる人が非常に多いのですが
現実には、Listの生成時のクラスを頻繁に書き換えるということはまずありません。
ArrayListと書いて本番運用後もそのまま使用され続けることが多いでしょう。
また、「容易」と言っても実質的には数文字の編集を減らせるだけです。
さらにいえば、コピペの回数が1回減らせるというだけのメリットしかありません。
私は本質的にどういう意味があるのかをゼロベースで考えたいと思っていました。
追記しました。

●ケースAでListを使う場合のメリットとデメリット

◎メリット
・クラスを変更する際に修正にかかる文字数が少なくてすむ
・独自メソッドを使用してしまうかもしれず、
 独自メソッドを使用してしまった場合、他の実装クラスに交換しにくくなる
・初学者に対し「こんな書き方が出来るんだよ」と示すことが出来る
・プロジェクトの都合で記述を統一したいときに「とりあえずListと書いとけ」
 というルールにすると単純で守られやすい

◎デメリット
・勝手に変えられると困るときでも、交換自由かのように見える
・独自メソッドを使用できず、他の何らかの方法で代用しなければならない
・変数の宣言とオブジェクトの生成箇所が離れているときもしくは
 複数の箇所でオブジェクトの生成をしている場合で、かつ
 クラスの変更を行なう際に、修正し漏れが発生しうる

◎その他
・「Effective Java」に「Listと書け」っぽい事が書いてある
 ※いつでもそれでいいとは書いていない


「他にもあるよー」という方はあとでもいいので追加してください。
とりあえずケースAは一段落したと思うので、ケースCに行きたいと思います。

ケースCの場合、すなわちメソッドの引数の場合です。
これは私にとっては自明なのですが…。


例えば、デバッグ用もしくはアクセスログを出力するためのメソッド等で
オブジェクトの中身を出力したい場合で、toStringを実装していればいい
というときには引数はObjectにすべきだと思います。
前提として独自クラスはtoStringを実装している事になりますが、
それはJavaコーディングの最低限のマナーとしてそうしておけよということで
実装していない場合は例外とさせてください。

で、Collection系で要素の数も出したい場合には、
ObjectではなくCollectionで宣言しておくべきだと思います。

※この場合、Listで宣言しなければならないケースが思いつきませんでした。


型は何が必要かをきちんと考え判断して使い分けるべきだと思います。
メソッドの引数の型はできるだけ抽象的なモノを使うべきだと思います。


これを表現するならば、209 もかまたりさんの
「文脈が成り立つ、一番抽象度の高い型」という言葉が当てはまると思います。
他にも何人かの方が同様のことをおっしゃっていたと思います。

また「Effective Java」の記述の「より一般的にオブジェクトを参照する」
というのはこのことを指しているのだと思います。


★「メソッドの引数の型には文脈が成り立つ、一番抽象度の高い型を使用すべき」
これに反論がある人っています?
>じゃまさん

メッセをさらしたのは、あなたが許可もなくメッセしてきたからです
しかもえらそうな物言いでね(笑

>残念ながら、Effective Javaは読んでますし、そこに書いてあるメリット自体は分かります。
>読んだのは一版ですが、8割くらいはその通り、その他はどうかってとこですね。
>ただ、自分の経験や考え、状況から、メリット・デメリットを勘案してそう書いています。

とても読んだとは思えないコメントばかりでしたけどねぇ・・・
読んだけど頭にはいらなかったってことですかね

それにしても「左辺は抽象度の高い型にすべし」という考えに異論があるのに「8割はその通り」などとよく言えたものです(笑

>私はEffectiv Javaに書いてあるから正しい、という考えはさらさらないので。
>「学びて思わざれば則ち罔し」て言葉知ってますよね?
>Effective Javaとか、デザインパターンとかばかり言う人は、この言葉を理解して無いんじゃないかとしか思えません。

ナンデスカコレハ?

「EffectiveJavaに書いてあるから正しい」と一体誰が発言したのですか?
「Effective Javaとか、デザインパターンとかばかり言う人」が一体どこで登場したのですか?

EffectiveJavaはJava言語の生みの親が絶賛している本です
もちろんEffetieJavaの著者はあなたよりはるかにレベルが高い
その人の考えが間違っていて、あなたの考えが正しいの?

そのような高邁さを以ってメッセージを投げられても、とても受け入れられるはずがありませんよ
>じゃまさん

あと、もういっこ

>> 最初から非機能機能まで強要するんですか
>> すごい教育方針ですね
>> それがちゃんとできてるとはとても思えないけど(笑
>これ、こっちでは当たり前です。
>強要した上でもちろんサポートする。
>PGというかコーダーとしか見ていないあなたのところでは無いでしょうけど。

これなんだけど、非機能要件を強要するのが当たり前っていうのは君のところ「だけ」って意味?
もしも君のところ「も」って意味なら俺は考えを改めなければいけない

非機能要件に対するアプローチの決定はできるだけ遅延させるのが常套手段だと思ってるんで
トピ汚し失礼いたします。

> chun さん
場合にもよるのであれだけど、知っているだけ損はないので、
行政で公開している、著作権法のページが以下にあって、
18条に公表権について書いてあります。一読しておくと良いです。

http://law.e-gov.go.jp/htmldata/S45/S45HO048.html

・その他参考(マイコミジャーナルの記事)
http://journal.mycom.co.jp/column/netlaw/023/index.html

知っておくだけ知っておいた方がと思います。
おどすつもり等、ありませんのでそこはご理解ください。
>> みうラスさん

揚げ足を取る用で恐縮なのですが、

>私もそう思います。何かが間違っていると思います…。
>ただ、そういう状況が存在しない事を前提として考えてしまうのではなく、
>そういうコードを書いてしまう人もいるという前提で捉えています。

という前提を置いて考えるのであれば、

>しかし、メソッドの抽出を含めリファクタリングそのものは
>細心の注意を払い行うべき作業だと思います。なので、
>うっかりSEにリファクタリング作業を任せること自体が問題だと思いますし、
>うっかりSEの負担軽減に注目することはややずれていると思います。

というのも事象としては同じレベルの話ではないでしょうか?

----
個人的にArrayListはListの実装としてはデフォルトの実装系として捉えているので、
ArrayListを選択するのに色々考える必要性はないものなのでは?と思っています。
逆にCopyOnWriteArrayListであったり、LinkedListと言ったような物は
特殊な事情があって利用されるものと思いますが、
これらの場合もその振る舞いを提供しているクラス外での変更を考慮する必要があるのか?
というところが視点になるのでは?と。

例えば同期コンテキスト内においてListnerを保持するようなListは
CopyOnArrayWriteListとして宣言されている必要はあると思いますし、
フィールドでの型もCopyOnWriteArrayListとして宣言すべきでしょう。
しかしそのクラスが持っているListenerの一覧を返す際はListで充分だと思います。

引数として受け取るケースだったとしても、Listで受け取ることが可能だけれども、
同期が保証されないとまずいケースで合った場合そのメソッド内で責任をもつべきことであって
外部に対して要求すべきかというとそうでもないような?
もちろんListでなく、特定の型でなければ動作が保証できない(代替手段がない)ようなケースであれば別とは思いますが。

このトピでずっと感じていた違和感なのですが、
特殊なケースにおいてその実装体型が何かということが
外部に漏れでてしまうということ自体がそもそもおかしいのでは?と。
それを考慮すべき箇所は一箇所にまとめるべきで、
CopyOnWriteArrayListを外部に対して強制的に使わせなければならないようなコードがあるのだとしたら
そこを如何にリファクタすべきかを議論すべきであって、
Listで宣言してはならないケースを議論すべきではないように思います。
若干トピずれしてしまってるのかもしれませんが、いかがでしょうか?
240 sawtootheadさん
> というのも事象としては同じレベルの話ではないでしょうか?

おっしゃりたいことはわかります。
うっかりSEに対し制限をかけるという点については同じです。
しかし異なる点もあります。

2つの話をごく端的に表現しますと以下のようになります。
・うっかりSEにコーディングをさせてはならない
・うっかりSEに全体に影響するリファクタリングをさせてはならない

うっかりSEに全体に影響するリファクタリングをさせない
ということは比較的容易にできると思います。
しかしコーディングの作業全般からはずすということは現実的に
難しいケースもあると思います。その違いと考えてください。


>Listで宣言してはならないケースを議論すべきではないように思います。
>若干トピずれしてしまってるのかもしれませんが、いかがでしょうか

抽象的なのでよくわかりません。
まず、ケースAについていえることですか?
ケースAのことではなくケースCについてのみいえることですか?
テーマに沿って具体的に指摘していただきたいのですが。

話をしているのは、例えばこの記述の場合で
【型名1】 list = new 【型名2】();

【型名1】を【型名2】と同じにするか異なるものにするか、その理由は?
という話をしています。
【型名2】を何にするかは重要ではありません。
大事なのは【型名1】に何を書くかです。

とりあえず「List」とかく人に、「なぜそう書いているんですか」
と問いかけをしているのだと思ってください。

そこまではOKですか?
【型名1】をテーマにしていること自体を問題視されているのですか?
> sawtootheadさん

同意です。

不思議に思うのは、EffectiveJavaを読んでいるという人がほとんどでありながら、そうとは思えない議論になっていることです。
一定水準の技術者なら読めば抽象プログラムを理解できるはずなんですけどね。

DIでは抽象は必須ですが、このトピックからJava技術者には抽象を理解していない者が少なくないようにも思えます。

この仮定の元では、プロジェクトでDIを採用するためには、抽象を知らない者への学習コストが嵩み、例えばガイドラインを厚くしなければならなくなるなど、あまり歓迎できない事態になるという結論になりえます。

結局、ソフトハウス全体が教育にコストをかけなくなったからこんな事態になってしまったのかなぁと思えてしまいます。
>>みうラスさん

返信遅れて申し訳ない。

自分が言っているのは

>【型名1】をテーマにしていること自体を問題視されているのですか?

こちらになります。

>とりあえず「List」とかく人に、「なぜそう書いているんですか」
>と問いかけをしているのだと思ってください。

とりあえずListと書く人、書く場合はListの実装がなんであるかを考える必要がないと判断してるからでは?と自分は考えます。

どういった振る舞いを求めるかによって左辺を導出出来ればいいのであって、実装型で考えなければならないケースは減らすべきと思っています。

何故Listがいいのかというのは、Listの制約に収まる範囲のみ考えれば済むからと考えます。
LinkedListやCopyOnWriteArrayListで宣言されていて、かつそれが引きずり回されるようなコンテキストでは正直コードを書きたくないですね。その一覧に対する追加や削除、取得といった振る舞いに制限を付けたかったりする場合(つまり考慮すべき事項がある場合)はそれを表現するオブジェクト(モデル)を作成すべきで、そのオブジェクトが許可する振る舞いとして表現すべきでは?と。

よそからもらってきたListに対してただ追加や削除しておしまいというケースが考えてみたんですがあまり浮かばなかったので、議論すべきところが違うのではないかなと思いました。

ここで議論されてるケースとして起こりうる間違いって既に存在してるインスタンスに対して新たに生成して代入しなおしてしまうから起きるケース、もしくはモデルに内包されているものではなく、生のListとして利用していて、本来モデルが制限すべき事項をListインスタンスに対して毎回考えなければならないケースのいずれかと思うのですが、認識が間違ってるでしょうか?

以下のように書いていくことでそういった問題は防げると思っていますし、そうでないのであれば先のレスでいったようにそういった形に持っていくにはどうすれば?どうするのがよりよいか?を議論すべきでは?と思った次第です。

class Something {
private CopyOnWriteArrayList<Listener> lisners = new CopyOnWriteArrayList<Listener>();

public void addLisner(Listener toAdd) {
// 考慮すべき制約があればここに
listeners.add(toAdd);
}

public void removeListener(Listner toRemove) {
// 考慮すべき制約があればここに
listeners.remove(toRemove);
}

public List<Listener> registeredListeners() {
// 外部での変更は許さない
return Collections.unmodifiableList(listeners);
}

}
本線からはずれるようなので、スルーしてもらって構いません。

# 236 みうラスさん
> ★「メソッドの引数の型には文脈が成り立つ、一番抽象度の高い型を使用すべき」
> これに反論がある人っています?

反論ではないのですが、2つだけつづりたくなりました。
ただし、オブジェクト指向とはあまり関係ないです。

私は割と古いタイプなので、メソッドの型はそれなりに実体を想定して作ります。
※殆どC開発時のクセみたいなものです。
その観点からいくと、余計であっても想定される実体に対して、
"必ずしも必要ではない制限"をかけるということに対して抵抗がなかったりします。
※メンテナンス性や拡張性の面が主です。

インスタンスの殆どをArrayListと想定するならば、
メソッドの内容を問わず、Listにしておくと、
Collection, Iterableという機能を踏襲しているため、
その内容が後々保証されますよね?

ので私の場合、必ずしも
> ★「メソッドの引数の型には文脈が成り立つ、一番抽象度の高い型を使用すべき」
の「すべき」には違和感があります。

もちろん、その制限をすることで、他のインスタンス実体が無意に大きくなることが予想される
一般ケースでは必ずしも当てはまるものではないと思っています。
自己フォロー・・・すみません。。。
> 反論ではないのですが、2つだけつづりたくなりました。
の部分に掛かる内容が、非常に抽象的にになったので要約を入れます。

・デメリットが無いかぎり、ある程度の拡張性を見込んだ型を指定しても良いと考えます
・デメリットが発生するならば、ある程度まで制約を落とす方が良いとも考えます
243 sawtootheadさん

>>【型名1】をテーマにしていること自体を問題視されているのですか?
>
>こちらになります。

どうしても考えたくなければトピの議論に参加しないという選択肢もあります。


>何故Listがいいのかというのは、Listの制約に収まる範囲のみ考えれば
>済むからと考えます。LinkedListやCopyOnWriteArrayListで宣言されていて、
>かつそれが引きずり回されるようなコンテキストでは
>正直コードを書きたくないですね。

Listの制約に収まる範囲で済むとどうなるのですか?何かうれしい事があるのですか?
「引きずり回されるようなコンテキスト」とは具体的にどのような記述で
どのような影響があるのでしょうか?

このトピで議論をしたいのは本質的なメリットやデメリットです。
書きたいか書きたくないか等の個人の嗜好を問うているわけではありません。
「どのようなケースにどのように影響するのか」それをより具体的に
論理的に考えたいのです。そういう点をご理解いただきたいです。

抽象的に大雑把に話しても意味は無いことはこのトピの前半で分かりましたので
具体的に話をしていただきたいです。
244 mmikeさん
>インスタンスの殆どをArrayListと想定するならば、
>メソッドの内容を問わず、Listにしておくと、
>Collection, Iterableという機能を踏襲しているため、
>その内容が後々保証されますよね?
>
>ので私の場合、必ずしも
>> ★「メソッドの引数の型には文脈が成り立つ、一番抽象度の高い型を使用すべき」
>の「すべき」には違和感があります。

よくわかりませんでした…。すみません。
できれば例に対して具体的にご意見・ご反論をお願いしたいです。


ケースC例1
デバッグ用もしくはアクセスログを出力するためのメソッド等で
オブジェクトの中身を出力したい場合(toStringを実装していればいい)

ケースC例2
デバッグ用もしくはアクセスログを出力するためのメソッド等で
オブジェクトの中身と(Collection系の)要素の数も出したい場合

私は
ケースC例1では、引数をObjectにすべきだと思います。
ケースC例2では、引数をCollectionにすべきだと思います。

これに対して具体的にご意見・ご反論をお願いします。


toStringしか使わないことが分かっているメソッドでも、
もしかしたら将来的にList系でしか使えないメソッドを
使うかもしれないので引数をListにすべき
ということですか?


>・デメリットが無いかぎり、ある程度の拡張性を見込んだ型を指定しても良いと考えます
>・デメリットが発生するならば、ある程度まで制約を落とす方が良いとも考えます

抽象度を上げるにしても下げるにしても、
おそらく必ずデメリットとメリットが発生します。
「デメリットが無いならいいことだね、デメリットがあるならダメなんじゃないか」
という程度のご意見に感じます。

どういう場合がメリットがデメリットを上回るのか、そういう点を
具体的に考えたいのです。
少し考えていたのですけれど、

List<Student> = new ArrayList <Student> ();

何でも入れられると困るというのは分かるのですけれど、
えーやん、実行時に評価してくれたら、とも思えます。

さらにJavaというかオブジェクト指向ではStudentをサブクラス化しようと考えますけれど
データベース的には学部を持たせることが一般的です。

結局
public class Student {
// ほげほげ
private Department department;
}
public class Department {
//ふがふが
private Collection students;
}

List studentList = session.getStudentList();

ここで、session#getStudentList()の実体を何にするのかを決めるのは
ビジネスロジックを書くひとが決めることになります。
データベースやさんと仲良くしなければならない理由はここにも起因します。

'#(x 0 #\Z)とか
(define (add-vector v1 v2)
(vector-map + v1 v2))
書けると便利ではありますし、AI関連では必要です。

Smalltalkは自己で完結していますから、aStudent store.ですみますが、
基本的にはRDBを利用するJavaでは難しい課題でありますね。
俺も要らない。実行時で十分。
初心者には価値はあるから否定はしないが、簡単になりすぎるのは教育上問題だな。

ログインすると、残り214件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Java 更新情報

Javaのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング