都元ダイスケ IT-PRESS このページをアンテナに追加 RSSフィード Twitter

最近は会社ブログしか書いてません。

2008-10-29

[]へんなSet

java.util.Set って、同じインスタンスを複数持たないよね。

Object o = new Object();
Set set = new HashSet();
set.add(o);
set.add(o);
set.add(o);
set.add(new String());

assert set.size() == 2;

違うインスタンスであれば、全部はいる。

Set set = new HashSet();
set.add(new Object());
set.add(new Object());
set.add(new Object());
set.add(new String());

assert set.size() == 4;

違うインスタンスであっても、同じクラスのインスタンスは複数入らないコレクションって、標準じゃぁ、ないよねー? 作るしかないかー。

ClassSet set = new HashClassSet();
set.add(new Object());
set.add(new Object());
set.add(new Object());
set.add(new String());

assert set.size() == 2;

こんなん。

追記

Set#add() の仕様を見ていて思った。equalsがtrueであれば入らないのか…。でもなんか気持ち悪いなー、equalsをこんな風にオーバーライドするのは…。

2008-10-24

[]ジェネリクスを使いこなそうゼ

というネタでエントリ書けよゴルァ、とid:happy_ryoに脅されて書くエントリー。

ジェネリクスご存知ですか。使ってますか。アノテーションと共にJava5から現れた、<> で囲まれた変な奴。

全くの余談ですが、アノテとジェネリクスの事を理解していなかったその昔。漠然と「たまに見かけるあの@とか、<> とかって何だろう」と思った訳ですよ。で、どうしようもなくて某所で聞いてみたんですね。そしたらさー、「ググれカス」って言われちゃってさwwww

Java @」とか「Java <>」で検索してみるわけですよw 無理だろww

はい、話し始める前から脱線してる都元ですコンバンワ。

ジェネリクス初心者がまず触れるのは、コレクションですかね。List<String>とかでお世話になる訳ですね。意図しない型のインスタンスを突っ込まれる心配もなく、取り出し時にキャストする必要もなくなる、なんか嬉しい奴、というイメージだと思います。

じゃあ、自分でジェネリクスを定義して使ってみようぜ、というのが今日のテーマ。いささか初歩的なんじゃなかろか、とか思ってたけど、某skypeチャットルームで世界の「Ryo Iwama」に脅されたので書いてみる。

ジェネリクスってgeneralの派生単語で、「一般」とかいう意味ですね。Java的な訳は「総称型」とか言ったりするようです。ではコイツは何を一般化して、何を総称してるのか。

ちょっと List のコードを見てみましょか。

public interface List<E> {
    boolean add(E o);
    E get(int index);
}

かなり省略しましたがw こんな感じです。ここで、add/getされる対象を「一般化」「総称」する役割を担ってるのがジェネリクスインターフェイスでは一般的(色んなモノに使えるように)に書いておいて、実際に使う時に用途を限定する、という使い方をします。

List<String> list = new ArrayList<String>();

って奴ですね。こうすることによって、一般的に書かれたListが、「Stringしか入れられないList」に特殊化する。

もうちょっと応用すると、こんな事もできる。

class StringList implements List<String> {
  // ...
}

こうして作られたStringList型にはStringしか入れられない。

じゃーさじゃーさ、Listインターフェイスに倣って、自分で色々クラスを定義してみようよ。

interface Processor<T> {
  T process(T input);
}

class StringProcessor implements Processor<String> {
  public String process(String input) { ... }
}

class IntegerProcessor implements Processor<Integer> {
  public Integer process(Integer input) { ... }
}

入力した何かを「処理(process)」するクラス。型が違っても一般的に書けました。

複数のジェネリクスを定義することもできる。

interface Converter<S, D> {
  D convert(S source);
}

class IntegerToStringConverter implements Converter<Integer, String> {
  public String convert(Integer source) {
    retrun source.toString();
  }
}

class MapToCollectionConverter implements Converter<Map, Collection> {
  public Collection convert(Map source) {
    retrun source.values();
  }
}

こんな感じか。というわけで「型だけ違うんだけど、似たような型を抽象化したい」って時に、ジェネリクスを自分で定義してみる、というのはいかがだろーか。

最後にオマケ。昔書いたネタだけど。

interface Hoge<T extends Exception> {
  void process() throws T;
}

class Fuga implements Hoge<FugaException> {
  public void process() throws HogeException { ... }
}

class Piyo implements Hoge<RuntimeException> {
  public void process() { ... }
}

ジェネリクスによって、投げる例外を一般化してる。しかも「Runtimeであれば、throws句がいらないの法則」を利用して、「チェック例外は投げません」ということを表現してみた。これはひどい

ココまで来ると、オシゴト的には誰も理解してくれなくなるので、やめましょうw

いじょ。

追記

そういえば、ふと思った。genericsで使う extends って、↑みたいな使い方するよね。で、コイツの仲間に super って居るよね…。

extendsは「コイツのサブクラス」という意味。superは「コイツの基底クラス」って意味…。今まで俺 generics の super って使ったことないんですが、どんな時に使うモンなんだろう…。有効な使い方が思いつきません><

2008-10-09

[]メソッドのアクセス制御

いやいや、忙しくてブログ更新サボっちまったぃ。まぁ、ぼちぼち書くつもりです。

メソッドのアクセス(可視性)を制御するために、しばしばアクセス修飾子(private, publicなど)を使うのはご存知の通り。書いたコードの可視性を、全てpublicにしても、変更前と同じ動作は出来ます。しかしー、オブジェクト指向では、この手法を使って「外に見える必要がないものは公開するべきではない」という情報隠蔽(information hiding)を実践していくコトが多いです。基本中の基本ですね。

自分、今まで「アクセス修飾子のみで」情報隠蔽を行って来たのですが、最近一つ学んだので書き記しておきます。

メソッドへのアクセス制御って、インターフェイスを使っても実践できるんですね。

インターフェイスには記述されていないけど、実装クラスには存在するpublicメソッド。例えば、あるクラスライブラリで、Factoryを使ってインスタンスを得て、インターフェイスでそれを受け取るケース。インスタンス的にはpublicメソッドを持っていても、インターフェイスには持っていない。

こうすることにより、そのメソッドへのアクセスパスを隠すコトができます。いざ、ライブラリ内で使用したくなったら、実装型にキャストするなり何なりで、使う事ができるようになります。

privateメソッドは、リフレクションでほじくり出さない限り、アクセスすることは出来ませんが、こういった「ソフトな」情報隠蔽というのも、柔軟でいいかもね〜、と思ったのでした。

[][]飲み会に参加してきた

第一回チキチキ 飲みにいったら偶然「ひがやすを飲み会」が隣りでやってた飲み会!!に飲みにいったら、偶然「ひがやすを飲み会」が隣りでやってたんですよ。うわーびっくり(棒

最近イベントに参加していなかったので、実は久々なメンバーが多かったかも。またちょくちょく飲みたいな〜。

最初は「マジメな」あっち側と、「いつもの」こっち側だったんですが、最後には入り乱れてとてもバランスの良い飲み会になったんじゃないかなww (一部、ymsr先生がイジられまくったり、といつもの感じももちろん…w)

こういった、ちょっと変質したjava-jaの雰囲気が楽しかった。ホラ、なんか自重しなさすぎる連中ばっかり集まるじゃん、いつもw

1000speakers:4に参加していた、という方もいて、あらためてゆっくりお話させていただきました。なんか俺って急速にメジャーになった人らしく*1、ナニをしたらそんなんになれるんですか、と純粋に質問されたので「うん、自重しないとこうなるミタイだよw」って言っといたw

どこかで何度か話しているけど、俺の人生のターニングポイントって、ことごとく「自重しなかった事の産物」だったりしている。

  • JJUGの創立総会に、懇親会まで単身で乗り込む。
  • 初参加初開催の勉強会(EclipSKY)でスピーカーをする。
  • 初参加の勉強会(java-ja:5 - チキチキMaven2)でスピーカーをする。
  • OSS(Dolteng)のコミッタやらない? と声掛けられたら「やらしてください」って言う。
  • 勉強会(1000speakers:4)のスピーカーに勝手に応募されても受けて立つw
  • SeasarConで喋る人募集してたらとりあえず申し込んで話す。
  • @ITで記事書きませんか?って言われたらそりゃ書く。

だいたいこんなトコロですかね。こんなコトしてると、いつの間にかこんなキャラになってます。みんな、自重いくないよw

*1id:itengineer辺りによく言われるんだけど、あんま自覚してないw