「Effective Java」は素晴らしい本であるが, 「Android開発では少し当てはまらないとこもあるよ」という話.
Effective Java for Android (cheatsheet). – RockNNull – Medium
インスタンス化させない
new を使ってオブジェクトを生成させたくない場合, private なコンストラクタを使いましょう. 特に, 静的なメソッドのみのユーティリティクラスで使うといいでしょう.
class MovieUtils {
private MovieUtils() {}
static String titleAndYear(Movie movie) {
[...]
}
}
静的なFactory
new を使う代わりに, private なコンストラクタを静的な Factory メソッドを使いましょう. これらの Factory メソッドは名前をつけることができ、毎回オブジェクトの新しいインスタンスを返す必要はなく、必要なものに応じて異なるサブタイプを返すことができます.
class Movie {
[...]
public static Movie create(String title) {
return new Movie(title);
}
}
Builder
3つを超えるコンストラクタパラメータを必要とするオブジェクトは, Builder を使ってオブジェクトを生成しましょう. すこし冗長かもしれませんが, 拡張しやすく読みやすいです. 値にクラスを使う場合は AutoValue を考慮するといいです.
class Movie {
static Builder newBuilder() {
return new Builder();
}
static class Builder {
String title;
Builder withTitle(String title) {
this.title = title;
return this;
}
Movie build() {
return new Movie(title);
}
}
private Movie(String title) {
[...]
}
}
// Use like this:
Movie matrix = Movie.newBuilder().withTitle("The Matrix").build();
イミュータブル化
「イミュータブル」とは, 生存している間は変化しないことです. オブジェクト内のすべての必要なデータは作成時に提供されます. これは, 簡単, スレッドセーフ, 共有性などさまざまな利点があります.
class Movie {
[...]
Movie sequel() {
return Movie.create(this.title + " 2");
}
}
// Use like this:
Movie toyStory = Movie.create("Toy Story");
Movie toyStory2 = toyStory.sequel();
すべてのクラスをイミュータブルにすることは難しいかもしれませんが可能な限りイミュータブルにします. (例えば, フィールドを private final に, クラスを final に). オブジェクトの生成はモバイル上では, コストが高くなる可能性があります.
静的なメンバークラス
外部に依存しないインナークラスを定義する場合, それを static にすることを忘れてはなりません. そうしないと, それぞれのインナークラスのインスタンスが外部のクラスの参照をもつことになります.
class Movie {
[...]
static class MovieAward {
[...]
}
}
すべてにジェネリクスを
Java は, タイプセーフティ(型安全) を提供しています. 可能であれば, プリミティブ型やObject型は避けましょう. ジェネリックスは、コンパイル時にコード・タイプを安全にしてくれるメカニズムです.
// DON'T
List movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = (String) movies.get(0);
// DO
List<String> movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = movies.get(0);
メソッドのパラメータや戻り値についても使うことができることを忘れないでください.
// DON'T
List sort(List input) {
[...]
}
// DO
<T> List<T> sort(List<T> input) {
[...]
}
すこし柔軟にするには, バインドされたワイルドカードを利用して, 受け入れる範囲を広げることができます.
// Read stuff from collection - use "extends"
void readList(List<? extends Movie> movieList) {
for (Movie movie : movieList) {
System.out.print(movie.getTitle());
[...]
}
}
// Write stuff to collection - use "super"
void writeList(List<? super Movie> movieList) {
movieList.add(Movie.create("Se7en"));
[...]
}
空の返却
リストやコレクションを結果なしで返却するときの null を避けます.
空のコレクションを返すことで, 簡単なインターフェースとなり, 偶発的な NPE を避けることができます. 新しいコレクションを作成するのではなく、同じコレクションを返すことをお勧めします。
List<Movie> latestMovies() {
if (db.query().isEmpty()) {
return Collections.emptyList();
}
[...]
}
String の連結
文字列を連結しなければならない場合、+演算子を使う場合があります.
多くの文字列の連結には使用しないでくだい. パフォーマンスは本当に悪いです.
代わりに StringBuilder を推奨します.
String latestMovieOneLiner(List<Movie> movies) {
StringBuilder sb = new StringBuilder();
for (Movie movie : movies) {
sb.append(movie);
}
return sb.toString();
}
例外を使った修正
私はエラーを示すための例外を投げることに賛成ではありませんが, 例外をチェックすることで、エラーを修正することができます.
List<Movie> latestMovies() throws MoviesNotFoundException {
if (db.query().isEmpty()) {
throw new MoviesNotFoundException();
}
[...]
}
再度, 見直してみるといいのかもしれません.
Ask HN: Why is “advice in Effective Java considered inappropriate for Android”? | Hacker News
Radio Hacker News -Translation - Android Apps on Google Play