IT戦記

プログラミング、起業などについて書いているプログラマーのブログです😚

Effective Java 読書会 2 日目 「equals night」

はじめに

今日もお疲れ気味な君の右足にローキックどーん
ってな感じで
どーん

今日読んだところ

20 ページ〜 44 ページ

とりあえず Eclipse をインストールしました!

わーわーパチパチ。
とりあえず、わからずに JavaEE エディションにしたら、
Super Java Hacker の @hikoma っくすに「普通ので良かったのにー」と言われちょっとしょんぼりーぬ(´・ω・` )
気をとりなおして

static イニシャライザ

public class Sample001 {

    public static final Date HOGE_DATE;

    static {
        HOGE_DATE = initDate();
    }

    // (snip)
}

みたいな?

static イニシャライザでのエラーってどうするのん?

握りつぶして、ロガーに出すのがいいと思うという話でした。

初回実行時初期化のダメなところ

まず、ダブルチェッキングとか煩雑な書き方になるってのはもちろんある。
それと、経験的にクラス A の初期化時にクラス B の値を見に行ってクラス B からまた A にという「初期化、卵と鶏問題」が発生しやすいという話も出た。
よppっぽどの理由が無い限り static イニシャライザ使えと

Office Lady?

え、 OL?
ああ、 0L ね。Zelo Long ね。
ああ、フォントが悪いなー

キャッシュのメモリリークに気を付けろ!

Servlet でメモリがどんどん増えてくときって、大概キャッシュの消し忘れだよね。
Stack や HashMap など、自分でメモリを管理するときは、要らなくなったオブジェクトの参照が繋がったまま増加していかないか注意する

いいヒーププロファイラってある?

あまり使ったことないなー。
こんど調べてみたいねって話になった。
ちょっと話はそれて、 jconsole 便利だよねって話もした

WeakHashMap って使ったことある?

あまり使わないなあ、と言う意見が多数。
たしかに GUI コンポーネントとかで、イベントターゲットを実装するときはいいかもなーと思った。

かなり、ありそうなパターンだなーっと。
そういう場合は、リスナーが WeakHashMap とかになってればいい

ファイナライザー

まず、使わない。普通は使わない。使ったことない。
finally 便利よね。
ファイナライザーァァァァガーディアアアアアアン!!!!ってかっこいいねって話になった
あと、 finalize って super のやつは自動で呼ばれないんですね。

equals

かるがるしくオーバーライドしたら。ダメ。絶対。
実際、そんなにオーバーライドするケースってないなーという話になった。

equals 4 契約

x != null && y != null && z != null の場合

  • x.equals(x) は必ず true (反射的)
  • x.equals(y) == y.equals(x) は必ず true (対称的)
  • x.equals(y) && y.equals(z) が true なら x.equals(z) は必ず true (推移的)
  • x.equals(y) はオブジェクト内の値が変わらない限り、何回呼び出しても同じ結果 (整合性)

たとえば

データベースからスケジュールのデータを持ってきたとして
そのスケジュールが持っている会議室オブジェクトと
他の同時刻にあるスケジュールが持っている会議室オブジェクトを比較するとしたら equals をオーバーライドしてやるべき?

やらないべき。roomA.equals(roomB) じゃなくて、 roomA.getID().equals(roomB.getID()) とやるべき。会議室の名前は、変わる可能性があるから

という話になったような気がしたけど、でもデータベース上の ID は一つだから
equals の実装が ID を使っていれば equals を使ってもいいような気がしてきた。
会議室の名前は significant なのかどうか。うーん
あれー。うーん。まだ理解出来ていない
週末の宿題にしようと思う

equals をオーバーライドしたら hashCode もオーバーライド

その件は次回

そのほかの話題

Maven の使い方を教えてもらった!
Maven は .m2 ディレクトリの育てゲーらしい

ちなみに

次回の読書会は明後日。明日は出席できない人が多いらしい。

ちょっと工作

なんか Eclipse を入れたのでちょっとプログラムを書いてみた。

キー検出

そのパソコン内でキーが押されたことを検出(Java がアクティブじゃなくてもいい)
キーロガーに使えるよ!!!(まて

package jp.co.cybozu.amachang;

import org.eclipse.swt.internal.win32.OS;

public class Key {
    
    /**
     * No constructor.
     * This is utility class.
     */
    private Key() {
        throw new AssertionError();
    }
    
    /**
     * Check key is pressed from previous calling.
     * @return true if key is pressed.
     */
    public static boolean isPressed() {
        for (int keyCode = 'A'; keyCode <= 'Z'; keyCode++) {
            
            final short state = OS.GetAsyncKeyState(keyCode);
            
            if ((state & 0x8000) != 0) {
                return true;
            }
        }
        return false;
    }
}
これを使って、パソコンを触っている間は、5 分置きに ping を打つアプリ作りました

在籍管理用にー

ジョブ管理して
package jp.co.cybozu.amachang;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.transform.TransformerException;

import org.apache.http.client.ClientProtocolException;
import org.xml.sax.SAXException;

public class Secretary {
    private HashMap<Job, Job> eventMap = new HashMap<Job, Job>();
    
    public interface Job {
        
        void run() throws ClientProtocolException, IOException, SAXException, TransformerException;

        boolean shouldRun(boolean isPressed, Date now, Date lastPressedTime);
    }
    
    public void reserve(Job job) {
        eventMap.put(job, job);
    }
    
    public void cansel(Job job) {
        eventMap.remove(job);
    }
    
    public void run() throws InterruptedException, ClientProtocolException, IOException, SAXException, TransformerException {
        Date lastPressedTime = new Date();
        while (true) {
            final boolean isPressed = Key.isPressed();
            final Date now = new Date();
            final Iterator<Job> iterator = eventMap.values().iterator();
            while (iterator.hasNext()) {
                final Job job = iterator.next();
                if (job.shouldRun(isPressed, now, lastPressedTime)) {
                    job.run();
                }
            }
            if (isPressed) {
                lastPressedTime = now;
            }
            Thread.sleep(100);
        }
    }
}
main
package jp.co.cybozu.amachang;

import java.io.IOException;
import java.util.Date;

import javax.xml.transform.TransformerException;

import org.apache.http.client.ClientProtocolException;
import org.xml.sax.SAXException;

import jp.co.cybozu.amachang.Secretary.Job;

public class PingTimeCard {


    /**
     * @param args
     * @throws InterruptedException 
     * @throws IOException 
     * @throws ClientProtocolException 
     * @throws TransformerException 
     * @throws SAXException 
     */
    public static void main(String[] args) throws InterruptedException, ClientProtocolException, IOException, SAXException, TransformerException {
        Secretary secretary = new Secretary();
        
        secretary.reserve(new Job () {

            private Date lastPingTime = new Date();

            @Override
            public void run() throws ClientProtocolException, IOException, SAXException, TransformerException {
                lastPingTime = new Date();
                System.out.println("ping at " + lastPingTime + ".");
                TimeCard.ping();
            }

            @Override
            public boolean shouldRun(boolean isPressed, Date now, Date lastPressedTime) {
                return isPressed && (now.getTime() - lastPingTime.getTime() > 300000);
            }
            
        });
        
        secretary.run();
    }
}

まとめ

明後日もがんばるぞー!