up: 📁Java
Java言語に関わること.
未整理
過去メモ. 少しずつ整理する.
Java プログラム実行方法
コンパイル
- javac コマンドでコンパイル.
- .java から .class ファイルを生成する.
javac -cp jar/netty-3.6.10.Final.jar src/Program.java実行
- java コマンドで実行.
- -cp で classpath を指定.
java -cp .;jar/netty-3.6.10.Final.jar;src Programサンプルから学ぶ classpath の設定と Java プログラムの実行 - Java 入門
Hello World
public class HelloWorld {
public static void main (String[] args) {
System.out.println ("Hello World !!");
}
}ビルドツール
Apatch Ant
Apatch Maven
Gradle
-
特徴
次から引用: ビルドツール Gradle のインストールと使い方 - @ IT
- Groovy でビルド手順を記述
- Apache Ivy ベースの強力な依存関係管理
- 人気の IDE (Eclipse, NetBeans) でも使える
- Ant ビルドの呼び出しもできる
Java 文法
interface
内容に抽象メソッドしか持たないクラスのようなもの.
class InterfaceImpl implements Interface1, interface2, interface3 {
...
}extend
継承.
interface,extend,implement のちがい
誤解しやすいので整理しておく.
以下の関係がある.
- interface と implements
- class と extends
Java では, 多重継承を許可していない. ひとつの class を extends で継承したら, 別の暮らすは interface として宣言して, implements として Mix-in する 必要がある. Ruby でいうところの, < と include の関係と同じ.
Enum
識別子をそのまま有限集合として持つ抽象データ型. とくに, Java では Enum は特殊なクラス.
Effective Java での Enum まとめ.
int enum パターン
名前つき int 定数のグループを宣言すること.バッドノウハウ.
public static final int FOO = 0;
public static final int BAR = 1;- コンパイラによる型検査の恩恵を受けることができない.
- 同じ名前がついたものを名前空間で区別することができない.
- 変更により再コンパイルが必要.
- 表示可能な文字列へ変換する方法かない.
- int と enum では実効速度はそれほどかわらない.
定数固有メソッド実装 (constant-specific method implementation)
enum 定数に対して振る舞いを関連付けるための方法.
パターン適用前.
public enum Operation {
PLUS, MINUS;
double apply (double x, double y) {
switch (this) {
case PLUS: return x + y;
case MINUS: return x - y;
}
throw new AssertionError () ("Unknown op:" + this);
}
}パターン適用後. enum 型で抽象メソッドを宣言して, 定数固有クラス本体で, 定数ごとに具象メソッドでその抽象メソッドをオーバーライド.
switch 文を排除するので, エレガント!! 抽象メソッドによって実装をカプセル化.
public enum Operation {
PLUS { double apply (double x, double y) {return x + y;} },
MINUS { double apply (double x, double y) {return x - y;} };
abstract double apply (double x, double y);
}定数固有クラス
さらに, 定数固有データと実装を組み合わせることで, 強力な表現力を.
public enum Operation {
PLUS ("+") { double apply (double x, double y) {return x + y;} },
MINUS ("-") { double apply (double x, double y) {return x - y;} };
private final String symbol;
Operation (String symbol) { this.symbol = symbol; }
@Override public String toString () { return symbol; }
abstract double apply (double x, double y);
}Enum の toString は定数表現は 文字列へ変換することもできる.
戦略 Enum (Strategy Enum)
抽象メソッドをクラスに変更して外部から与えてやるようにすれば, これはいわゆる Strategy Pattern だ.
評価戦略を外部から与えて, Operation は委譲で評価をする.
public enum Operation {
PLUS (StrategyType.PLUS), MINUS (StrategyType.MINUS);
private final Strategy strategy;
Operation (EvaluateType type) {
this.type = type;
}
double apply (double x, double y) {
return type.evaluate (x, y);
}
// Strategy Enum Type
private enum EvaluateType {
PLUS { double apply (double x, double y) {return x + y;} },
MINUS { double apply (double x, double y) {return x - y;} };
abstract double apply (double x, double y);
}
}enum 定数と値の関連付けに ordinal をつかわないこと
enum と関連付けられた int 値を取得するメソッドとして ordinal メソッドがある.
これを定数と値を関連付けるときには, 使わない. なぜなら, コードの修正で, 振られる番号が変わるから.
public enum Number {
ONE, TWE;
public int getNumber{ return ordinal () + 1; }
}代わりにインスタンスフィールドを利用すればよい.
public enum Number {
ONE (1), TWE (2);
private final int number;
Number (int number) { this.number = number;}
public int getNumber{ return number; }
}集合と集合の対応づけに序数インデックス (配列) をつかわない
2 つの集合を対応付けるときには, 配列をつかうよりもいい方法がある.
それは, EnumMap. EnumMap は内部実装は配列でされているものの, インデックスを意識する必要がないというメリットがある.
配列をインデックスするために序数を使用することが適切であることはほとんどない.代わりに, EnumMap を使用すること.
関連が多次元ならば, EnumMap<…, EnumMap<…>> というように連なっていく.
Map<Herb.Type, Set<Herb>> herbsByType =
new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);
for (Herb.Type t : Herb.Type.values ())
herbsByType.put (t, new HashSet<Herb>());
for (herb h: garden)
herbsBytpe.get (h.type).add (h);内部クラス: Inner Class
他のクラスの内部に宣言されたクラス. ネストクラスともいう.
以下の 4 つに分類できる
- static メンバクラス
- 非 static メンバクラス
- 無名クラス
- ローカルクラス
内部クラスの主な役割は, 外側のクラスの Utility.
static メンバクラス
とくに理由がない限り, 内部クラスは private static をつける.
static をつけないと, 親のクラスがインスタンス化されるとともに, 子もインスタンス化される.
それはすなわち, 不必要な時間とメモリの消費になるので.
非 static メンバクラス
主な使いどころは, Adapter パターンを委譲で実現するとき.
ジェネリックスも合わせて利用される.
無名クラス
主な使用目的は, 関数オブジェクトを生成するため.
Java7 以前は, Java でクロージャを実現するためには, 無名クラスを利用する必要がある.
Java8 だと lambda があるので, 無名クラスの使いどころがないかも.
無名クラスは, プログラムの途中にかかれるので, 可読性のためには, せいぜい 10 行程度の短いものが適切.
ローカルクラス
あまりつかわない.
Cuncurrency
Thread
Java で Thread を利用する方法は 2 つある.
Thread の継承
Thread クラスを利用する.
public class MyThread extends Thread {
public void run () {
// code to run
}
}
Mythread myThread = new MyThread ();
myThread.start ();Runnable I/F の実装
スレッドを実装するクラスが別のクラスのサブクラスでなければならない時に Runnable インタフェースを使用する. Java は多重継承をサポートしていないので.
public interface Runnable {
public void run ();
}
public class Myrunnable implements Runnable {
public void run () {
// code to run
}
}
Myrunnable myRunnable = new Myrunnable ();
new Thread (myRunnable).start ();ExecuterService
ThreadPool
複数のスレッドをあらかじめ作成して待機させておき, タスクが来たら待っているスレッドにタスクを割り当てて処理を開始させる仕組みをスレッドプールと言います
Java Annotation
クラスやメソッド, パッケージに対してメタデータとして注釈を記入する.
3 つの種類がある.
- マーカー・アノテーション ・・・ データが無く名前だけを持つアノテーション.
- 単一値アノテーション ・・・ データを一つだけ持つアノテーション. 見かけはメソッド呼び出しに似ている.
- フル・アノテーション ・・・複数のデータを持つアノテーション.
開発環境・ツール
Emacs
📚Effective Java
- 『 Effective Java 第 2 版』正誤表
- Effective Java のソース: marhan/effective-java-examples
- Effective Java のまとめのまとめ - Qiita
第 2 章 オブジェクトの生成と消滅 (項目 1 〜 項目 7)
第 3 章 すべてのオブジェクトに共通のメソッド (項目 8 〜 項目 12)
第 4 章 クラスとインタフェース (項目 13 〜項目 22)
継承をやたらと敵対視している
-
継承よりもコンポジションを選ぶ継承は不必要なメソッドを公開する. つまり, 継承はカプセル化を破る.
-
継承をつかうならば設計を文書化する, でなければ禁止だ.
-
抽象クラスよりもインタフェースを選ぶ実装の観点では,
- 抽象クラスはメソッドに対する実装を含むことを許されている.
- インタフェースはメソッドに対する実装を含むことを許されていない.
機能の観点では,
- 抽象クラスはある機能の実装を強制する.
- インタフェースは任意の機能を混ぜ合わせる.
階層化の観点では,
- 抽象クラスは物事を階層化することに優れる.
- インタフェースは階層を持たないものをまとめることに優れる.
インタフェースは, 階層を持たない型システムを構築する.