Java
作成日時:2024-08-01以前
更新日時:2024-08-26
列挙型とファクトリー
値オブジェクトによる普遍性
関心事を纏めておけば修正箇所はわかりやすい
修正するとき何処を直せばいいかすぐわかるような。
リフレクションはキャッシュする
Math.ceil(1/2)が1にならない
1/2が0に評価されるから。
どちらかをdoubleにキャストする。
Enum
- values()で返却される配列は、定義順が保証されている。
- クラス名の末尾にEnumをつけない。単数形の名詞であること
- EnumSet, EnumMapを使え
Stream
- コレクションにnullが存在する状態で、findFirst()を呼ぶとNullPointerException
マルチスレッド
基本的にはFuture#getとCallableでスレッドの完了を待てばいいが、
各スレッドが終わった直後に何かをしたければ、CompletableFutureで
JavaScriptのPromiseみたいなことができる。
モジュール
Javaのモジュールに関して。
モジュールは下記の認識。
- モジュールとはパッケージの集合体である
- 公開するパッケージを表明できる
- 依存するパッケージを表明できる
- クラスパスとは異なるモジュールパスという概念がある
Javaプロジェクト内に下記のパッケージが存在するとする。
- com.example.a.util
- com.example.a.common
- org.example.b.util
- org.example.b.common
module com.example {
exports com.example.a.util,org.example.b.util
}
として単一のjarを生成した場合、
末尾utilのパッケージのみが外部から参照される認識
- パッケージ版デメテルの法則
- パッケージ版カプセル化
みたいに考えればよろし
requiresで本当に必要なモジュールを明示できる
それ以前は関係ないものを読み込んだりする可能性があった
でもmavenやgradleがあればあんまり恩恵はない
インターフェイス
- staticメソッドはファクトリとかUtilとか
- 単一責任原則的な
- defaultメソッドはtemplate method的に
Optionalでnull合体演算子
Optional.ofNullable(obj).orElse(default)
Gradle
Springを使わずに構築するのが久々だから、そこそこ詰まった。
Eclipseから作成すると、デフォでマルチプロジェクトになるよう変わっていた。
シングルプロジェクトが作りたかったので、下記の手法でプロジェクトを作成した。
導入からプロジェクト作成
- Gradle Build Toolからzipをダウンロード
- zipを解凍し、任意の場所に配置
- binフォルダにpathを通す。
gradle init
でプロジェクト作成。対話形式。- タイプは4のBasicを選ぶ
- 出来たプロジェクトをeclipseにインポート
Gradleの同期が終わらない
15%前後から進まなくなった。
設定 > Gradleから「ビルド・スキャン」のチェックを外す。
可視性
- protected:自身とサブクラスのみ。孫は含まない。
- なし:パッケージ内のみ。
ラムダ
forEachの中のラムダ式が検査例外出す奴だと、try-catchで囲まなければならないからめんどくさい。
これに限らず、いろいろとforの方がよい。
ラムダは単純なstream処理と、関数インターフェイスとかで使用すべき。
ジェネリック
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
public class Sample {
public static void main(String args[]) {
List<GenericClass> list = new ArrayList<GenericClass>();
list.add(new GenericClass<Integer>(1));
list.add(new GenericClass<String>("2"));
//list.add(new GenericClass<Object>(null)); // エラー
list.forEach(item -> item.output());
}
// 多数の境界
private static class GenericClass<T extends Serializable & Comparable<T>> {
public T value;
public GenericClass(T value) {
this.value = value;
}
public void output() {
System.out.println(value.toString());
}
// 境界ワイルドカード
public void method(List<? extends T> list) {
List<Integer> IntegerList = new ArrayList<>();
List<? extends Number> longList = list;
}
}
}
共変
総称型G(T)において型Xを型Yに変換できる際、G(X)がG(Y)に変換できる場合、
G(T)は共変性を持つという。
配列は共変性を持つ。
Object[] o = new Integer[3];
総称型は基本的には持たない。不変(invariant)
境界ワイルドカードで共変性を持たせる。
コレクション変換
Listから特定の項目をキーにMapを生成
かつ、最初の要素を適用する方法。
// 元のリストから重複を除いてMapにする
Map<String, Person> map = personList.stream()
.collect(Collectors.toMap(
Person::getId, // キーとしてidを使用
person -> person, // 値としてPersonオブジェクトを使用
(first, second) -> first // 重複時は最初の要素を保持
));
// Mapの値をリストに変換
List<Person> uniqueList = new ArrayList<>(map.values());
並列処理/マルチスレッド
色々種類はある。
Threadよりかは、ThreadPoolExecutorかCompletableFutureを使った方がいいか。
前者は複数タスクを並列で処理したい時。
後者は単一の処理を非同期で行いたいときとか。(JavaScriptのPromiseっぽい感じ)
使い分けは上記の通りでなくともよいし、組み合わせて使うこともできる。
仮想スレッドを指定できる。
その他
- カプセル化 全て隠蔽
- コレクションメンバー変数もgetter準備せず、追加を外部に許可させるためadd関数作ったり。
- デメテルの法則
- Enumがない言語はクラスで代用すればいいじゃん。
コンストラクター隠蔽して内部に定数つくってさ。 - メッセージ引数は列挙型
- 野良IDを防ぐ
- ジェネリックメソッド
- BCrypt
Java secureRandom - BigInt