はじめに
この記事は、以前書いたコーディング規約の更新版となります。以前記事を書いてから、Androidでの開発言語に本格的にKotlinが入って来たことや、DataBindingやその他もろもろの新しいスタンダードな手法が現れてきたことなどを踏まえて2016年版として更新したものになります。
こちらは、Javaでの開発を想定した規約となりますが、命名規則の部分についてはKotlinとJavaどちらでも使えるようにと考えて書いています。
もし、Kotlinのコーディング部分での規約をお求めの方はこちらの記事も合わせて読んでいただければと思います。
http://qiita.com/Reyurnible/items/be68b2207e33a0b78936
コーディング規約について
このコーディング規約は、AndroidアプリケーションをAndroidStudioとJavaを用いて開発することを念頭に置いて作成されており、それ以外のツールの使用を想定していません。
また、規約はGoogleが提唱するAndroidのコーディング規約と、Sunmicroシステムが提唱するJavaのコーディング規約を合わせて作成されています。時間があれば、そちらの規約についても確認してみましょう。
本記事で使用する表記方法一覧
記法名(フリガナ) | 基本 | 語頭 | 区切 | 例 | 用途 |
---|---|---|---|---|---|
UpperCamelCase(アッパーキャメルケース) | 小文字 | 大文字 | 大文字 | HogePiyoFuga | クラス名など |
lowerCamelCase(ローワーキャメルケース) | 小文字 | 小文字 | 大文字 | hogePiyoFuga | 変数名・関数名など |
snake_case(スネークケース) | 小/大文字 | 小/大文字 | 小/大文字 | HOGE_PIYO_FUGA | 定数・略語を含む単語など |
lower_snake_case(ローワースネークケース) | 小文字 | 小文字 | 小文字 | hoge_piyo_fuga | 各種リソースなど |
1.命名規則について
App(Application)
アピリケーション名(Application Name)
- 普通の英語名(スペースを含んでも構わない)
- UpperCamelCase
ソースコード(Src:Sorce)
パッケージ名
- すべて小文字
- スペースは削除して、そのままつなげるか
.
で階層を1つ深くする - srcの中のパッケージ名:
- メインパッケージ:<リバースドメイン名>.<アプリケーション名>(自動で生成される)
クラス名
- UpperCamelCase
- 名詞の組み合わせを用い、省略しない。
- Activity、Fragment、AdapterなどはComponent名を末尾に付ける
- Activityなどのレイアウトをもつビュークラスは、リソース名と関連性のある名前にする
例 | 補足 |
---|---|
Hoge | |
HogeHuga | |
HogeActivity | リソース名:activity_hoge.xml |
HogeFragment | リソース名:fragment_hoge.xml |
HogeView | view_hoge.xml ※ある場合のみ |
HogeAdapter |
定数名(public static final)
- 大文字とアンダースコア(_)のみを用いる
ex:public static final double FIELD_WIDTH = 500.0; - 用途に応じて、以下のように接頭辞を変える。String型の識別子の値は、lowerCamelCaseに変換したものを使用する
用途 | 接頭辞 |
---|---|
Intentのaction | ACTION_ |
Permission | PERMISSION_ |
BundleやIntentのフィールド名 | EXTRA_(型名)_ |
なお、これらの定数の値は、パッケージ名で始める。 | |
public static final String ACTION_GPS_STATUS_CHANGED = "com.example.sample.ACTION_GPS_STATUS_CHANGED"; | |
public static final String EXTRA_GPS_LOCATION = "com.example.sample.EXTRA_GPS_LOCATION"; |
プロパティ名・変数名
- lowerCamelCase
- 変数名には名詞を利用し、省略しない
- アンダースコア(_)やドル記号($)は使用しない
- 配列やListなどのデータを複数持つものには、複数形(s)を使用する ※Listは、ListViewとの誤用のため、必ず複数形を使用することに気をつける
- Viewには、以下の表の通り名前の先頭にView名を付ける
Viewクラス | 接頭辞 |
---|---|
View | view |
TextView | text |
EditText | editText |
Button | button |
ImageView | image |
ImageButton | imageButton |
ListView | list |
GridView | grid |
ScrollView | scroll |
LinearLayout | layout |
FrameLayout | layout |
※~Viewが付いているものは、Viewをとったキャメルケースを使用し、Viewがついていないものについてはそのままキャメルケースとする。
※~Layoutが付いているものは、layoutとする。
String name = "hoge";
String[] names = new String[2];
List<String> names = new ArrayList<>();
TextView textName = new TextView(this);
※補足:SMSuffixについて、SMSuffixはJake Wearthonによる反対のツイートや、Kotlinで用いないこと、DataBindingを使用した際にView名から自動生成させる際にViewのIDをそれに合わせると気持ち悪いことなどから使用しないこととした。また、IntellijIDEAが高機能であり、メンバー変数と変数を誤認することが少なくなったこともある。
メソッド名
- lowerCamelCase
- 処理メソッドの名前は動詞から始める
- モデルクラスなどのアクセサメソッドについては以下の接頭辞を使用する
種類 | 接頭辞 | 例 |
---|---|---|
Boolean値を返すもの | is | boolean isHoge() |
プロパティ値を返すもの | get | String getHoge() |
プロパティ値をセットするもの | set | void setHoge(String hoge) |
Layoutから指定されるリスナーメソッドについて
- それぞれのリスナーによって以下の接頭辞から始め、その後にViewの名前か形容詞を繋げる形とする。
// idがbutton_addの場合
Button buttonAdd;
// onClickのプロパティに指定する、addButtonを押したときのメソッド
public void clickAdd(View v) {
}
// onLongClickのプロパティに指定する、addButtonを押したときのメソッド
public void longClickAdd(View v) {
}
データベース関連
- テーブル名とカラム名:小文字とアンダースコア(_)
- テーブル名:<モデルオブジェクト・クラス名>s
- IDカラム名:BasicColumns._ID
- データベース名:<アプリケーション名>.db
Res(Resource)
全てに共通して、resフォルダ以下はlower_snake_caseを使用するものとする。lower_snake_caseを使用する意図は、画像のファイル名など大文字を使えないケースがres
フォルダ以下だと度々発生するため、初心者への誤用を避ける意図と統一感を持たせるためである。
View
ViewのIDについては、DataBindingを使用するかや、好みに合わせて以下の選べるように何種類化のパターンを記述しておく。
Pattern1: 画面名を記載するパターン
このパターンは、画面名をViewのIDに使用することで、それぞれの呼び出しの際に画面名から書き始めた際にどのViewが画面内に配置されているかをわかりやすくする狙いがある。ただし、書く際の冗長さもあるため、画面名は頭文字を取るなど適時短縮化をすることをおすすめする。
- lower_snake_case
- 先頭には画面名を付ける
- 画面名の後に、表のViewに対応する名前を付ける
- View名の後には、名詞か動詞を使用する
※複数の画面で共通した役割を持つものについては、画面名を外した名前をids.xmlなどに記載し、その値を@id/
によって参照するようにする。
Pattern2: DataBindingを使用するパターン
DataBindingを行う際には、レイアウトファイルごとに勝手にIDの付いているオブジェクトの変数を用意してくれるため、Pattern1のような絞込をする必要がない。そのため、画面名を付けずに変数名の命名規則と自然と一致するような命名を行う。
- lower_snake_case
- 先頭には、表のView名に対応する文字を付ける
- View名の後には、名詞か動詞を使用する
View名のfixリスト
Viewクラス | 辞 |
---|---|
View | view |
TextView | text |
EditText | edit_text |
Button | button |
ImageView | image |
ImageButton | image_button |
ListView | list |
GridView | grid |
ScrollView | scroll |
LinearLayout | layout |
FrameLayout | layout |
※~Viewが付いているものは、Viewをとったスネークケースを使用し、Viewがついていないものについてはそのままスネークケースとする。
※~Layoutが付いているものは、layoutとする。
String
- lower_snake_case
- 先頭は数字から始めない
- 特定の画面でしか使用されないものには、画面名を接頭辞として付ける
- アプリ全体で使用する可能性のある文字列については、画面名を付けない
- それぞれの用途ごとに画面名の後に以下の名前を付ける
用途 | 辞 |
---|---|
タイトル | title |
テキスト | label |
ボタン | btn |
EditTextヒント | hint |
エラー | err |
Drawable/Mipmap
- lower_snake_case
- 先頭は数字から始めない
- 画像の用途ごとに表の接頭辞を使用する
用途 | 接頭辞 |
---|---|
アイコン | ic |
背景 | bg |
ボタン | btn |
その他 | img |
※画像ファイル名は、ファイル名によってはエラーになるケースがあるため気を付けること
※XML画像以外の先頭がimgから始まるリソースは、mipmapフォルダ側に格納する
Dimension
- lower_snake_case
- 先頭は数字から始めない
2.Javaコーディング規則
コーディング規則はGoogleのJavaのコーディング規則に従う
Google Java Style
###3.その他Javaコーディング規約と変更###
####型変換について####
基本的にvalueOfメソッドを用いて行う。
変換する対象の型名.valueOf(T)
####例外処理について####
#####例外を無視してはいけない#####
悪い例:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) { }
}
このように例外を無視していると、いつか誰かがつまずき、コードにある地雷を踏んでしまいます。コードにあるすべての Exception は処理しなければなりません。どのように処理するかは、場合により異なります。
例外の処理の仕方:
- メソッドの呼び出し元に例外を投げます。
void setServerPort(String value) throws NumberFormatException {
serverPort = Integer.parseInt(value);
}
- 適度に抽象化した新しい例外を投げます。
void setServerPort(String value) throws ConfigurationException {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new ConfigurationException("Port " + value + " is not valid.");
}
}
- catch {} ブロックのなかで行儀よくエラーに対処して、適切な値を代入しておきます。
/** Set port. If value is not a valid number, 80 is substituted. */
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
serverPort = 80; // default port for server
}
}
- Exception をキャッチして、新しい RuntimeException を投げます。しかし、これは危険です。この手段をとるのは、そのエラーが発生したときにはクラッシュさせるのがふさわしいといった積極的な理由がある場合のみにしてください。
/** Set port. If value is not a valid number, die. */
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new RuntimeException("port " + value " is invalid, ", e);
}
}
元の例外が RuntimeException のコンストラクタの引数に渡されていることに注意してください。もしJava 1.3でもコンパイルする必要があるなら、元の例外を省略する必要があります。
- 最後の手段: 自信をもって例外を無視するのが本当に適切だと言えるのであれば、例外を無視しても構いません。ただし、なぜそうするのか、きちんとした理由をコメントに入れておく必要があります。
/** If value is not a valid number, original port number is used. */
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
// Method is documented to just ignore invalid user input.
// serverPort will just be unchanged.
}
}
#####汎用的例外の使用について#####
悪い例:
try {
someComplicatedIOFunction(); // may throw IOException
someComplicatedParsingFunction(); // may throw ParsingException
someComplicatedSecurityFunction(); // may throw SecurityException
// phew, made it all the way
} catch (Exception e) { // I'll just catch all exceptions
handleError(); // with one generic handler!
}
ほとんどの場合、汎用の Exception や Throwable をキャッチするのは適切ではありません。また、できるだけ Throwable を使わない方が望ましいです。
汎用の Exception をキャッチする代わりに、次のような手段をとることができます。
- try の後、例外ごとに別の catch ブロックでキャッチする。これは不恰好に見えるかもしれませんが、すべての Exception をキャッチするよりましです。catch ブロックでは、同じコードを繰り返しすぎないよう注意してください。
- 複数の try ブロックを使って、きめ細かくエラー処理するようリファクタリングする。パースから IO を分離して、それぞれ個別にエラー処理するようにしてください。
- 例外を投げ直す。どうしてもこのレベルで例外をキャッチする必要がない多くの場合には、単にそのメソッドに例外を投げさせてください。
####インポートについて####
コードをインポートする際には、必ずワイルドカードを使用しないスタイルを使用する。
ただし、Java標準ライブラリ(java.util., java.io. など)とユニットテストコード(junit.framework.*)についてはその限りではない。
また、順序については以下のとおりに行う。
- Android 関係のインポート
- サードパーティ製ライブラリ (com, junit, net, org)のインポート
- java および javax 関連のインポート
各グループ内では、アルファベット順にインポートします。
大文字は小文字よりも前にあるものと見なします。(例えば Z は a よりも前にある)。
大きなグループ分け (android, com, junit, net, org, java, javax) の間には空行を入れておくべきです。
####メソッドについて####
メソッドはできるだけ小さく、ポイントを絞ったものにする。
目安として、40行を超えるようであれば、プログラムの構造に影響を与えることなく分割できないか検討する。
また、メソッドがスーパークラスにある宣言や実装をオーバーライドしているときには、 @Override アノテーションを必ず付ける。
####インデントについて####
ブロックのインデントにはスペース4つを使用する。タブは使用しない。
関数呼び出しと引数を含んだ行の折り返しは、スペース8つでインデントを行う
3.Layoutのコーディング
レイアウトは基本的に、階層が深くならないように配慮して書く。
####RelativeLayoutについて####
RelativeLayout を使用して記述する場合は、基準となる View から先に記述していき、先に ID をつけるようにする。
パディングについて
パッディングは、対象の要素の階層よりも一つ下の要素に対して余白を設けたい場合に使用する。
また、padding は使用せずに、padding-left、padding-top、padding-right、padding-bottom を使用し個別に指定するようにする。
マージンについて
マージンは、対象の要素と同一の階層の要素に対して余白を設けたい場合に使用する。
また、要素1と要素2がxmlで上から並んでいる場合。要素2にマージンを指定し、余白を作るようにする。
Width と Height について
fill_parent は使用しないようにし、match_parent を使用する。
また、後ほどコードから値を変更する可能性がある場合は wrap_content を指定しておく。dp によって絶対値指定する場合は dimen の値を参照するようにする。