概要
エンジニアになって1カ月、コーディング規約とかよくわかない!
そんな自分向けにとある本を引用しながらまとめて書きました
目次
規約
1 命名に関する規約
1.1 命名全般
1.★★★名前には英単語を使用する。
- 原則として英単語を使用する。
日本語をローマ字にしたものはやめること
>良い例
public void setOrderAmount()
>悪い例
public void setJuchukingaku()
2.★大文字と小文字で名前を区別しない
- コンパイラが大文字と小文字を区別することを利用した名前の区別はしません。
>良い例
Date birthday =
Date myBirthday =
Date nextBirthday =
>悪い例
Date birthday =
Date birthDay =
static Date BIRTHDAY =
- また紛らわしい命名も避けましょう
とても長い名前の最後の単語だけ異なる
GermanPotateSaladAndBoiledEggWithSalt
GermanPotateSaladAndBoiledEggWithSalsa
同じ単語の異なる省略語の乱用
tempFileName
tmpFileName
単語の単数形と複数形の区別
salesOrderDetail
salesOrderDetails
1.2 パッケージ
3.★★パッケージ名はすべて小文字にする
- パッケージ名には大文字を使わず、小文字に統一するのかJavaの基本ルール
- グローバルなパッケージ名は組織に割り当てられたインターネットドメイン名に基づいて命名します。
- パッケージ名の英単語は単数とします。
>良い例
com.fujitsu.fap.dashborad
>悪い例
//大文字
com.fujitsu.fap.ZZL050
//複数形が使われている
com.fujitsu.fap.libraries
- パッケージ部分が小文字で統一されていると、戦闘が大文字のクラス名が認識しやすくなります。
>例
com.fujitsu.fap.graph.RadarChart
- パッケージ名には省略語を使用しない
- パッケージ名にはフルスペルの単語を使用
- パッケージ名は長い名前になりがち
- 第三者がパッケージ名を理解しやすくするため省略後を使用せずに命名する。
>良い例
com.fujitsu.fap.dashborad
>悪い例
//省略語が使われている
com.fujitsu.fap.dbrd
javaではパッケージの使用利点が以下の通りにあります。
同じ役割をもつクラスやインターフェースを一つのパッケージにまとめることによって、そのクラスやインターフェースの持つ意味を分かりやすくする。
同じ名前を持つクラスやインターフェースが複数ある場合、名前の衝突を避けることができる。
5.★★インポートでは*を省略しない
- import文はクラス名をアスタリスク[*]で省略せずに記述します。
- import分で指定するクラスは、「パッケージ名.クラス名」で記述
- ただし、プロジェクトを横断的に機能する共通チームなどが提供するクラスやJDK、著名なオープンソースなどは利用を容認できます。
- 目安としては同時に3以上のクラスをimportする際には[*]を利用可能とします。
import java.util.Hashable;
import com.fujitsu.jcc.common.*;
import parts.dbcommon.EZDConnectionMgr;
import parts.dbcommon.EZDTBLAccesser;
importを多様する場合は可読性への配慮が重要
1.3 クラス
6.★★★クラス名は役割を表す名前にする。
クラス名を適切に命名することで、そのクラスの役割や責任が明確になります。
それによりクラスの持つフィールド(属性、フィールド)やメソッドの決定がぶれづらくなります。
-
クラスは1単語の命名を避けるようにする
- 2単語以上で命名するように
-
略称ではなくフルスペルの英単語を使うようにする
-
クラスの役割を連想できるクラス名が命名できない場合がある
- クラス定義の直前にコメントする
- そのクラスの正式な名前を日本語で記す
- クラスの目的や機能を記す
- 適用したデザインパターンや、アーキテクチャ上の役割がわかるように記す
- クラス定義の直前にコメントする
>良い例
SalesOrderSlip
AccountReceivableService
>悪い例
SBL01
- クラス名にプレフィックス(接続辞)を付けたい場合がある
- 基本的にはプレフィックスは可読性を下げる
- つける場合はアルファベット3文字等、シンプルに適用しましょう
- 基本的にはプレフィックスは可読性を下げる
>プレフィックス適用例
GSSSalesOrderSlip
GSMCustomer
- プレフィックスの使い方として画面IDや業務IDを使用する場合があります。
- クラス名全体を読みづらくなってしまうため基本デメリット
- コードが極端に長くならないようにコード体系の設計時から工夫をするようにする。
- クラス名全体を読みづらくなってしまうため基本デメリット
>画面IDのプレフィックス適用例
ODR0050SalesOrderSlip
MST0030CustomerEditor
>不適切な画面IDのプレフィックス適用例
//プレフィックスが長すぎる
ODR0050rev001SalesOrderSlip
//識別子に使えない「-」が画面IDに含まれている。
MST0030-001CustomerEditor
【用語辞書例】
日本語 | 英語 | 省略後 |
---|---|---|
売掛金 | account receivable | accrec |
受注 | sales order | slord |
登録 | register | regist |
7.★★★クラス名はPascal形式で記述する
-
クラス名は1以上の英単語で命名します
- 最初の一文字目を大文字とし、複数の単語を扱う場合は各単語を大文字とする。
-
また、単語の前後にはアンダースコア「_」やハイフン「-」やドル記号「$」を使用しない
>良い例
SalesOrderSlip
AccountReceivableService
>悪い例
sales
accounttreceivable
各単語の先頭文字を大文字にすることを「キャピタライズ」と言います
キャピタライズした文字列の形式を「Pascal形式」といいます(UpperCamel形式とも言います)
Pascal形式でのクラス名の表記はJavaの一般的なルールです。
8.★★★クラス名はフルスペルで記述する。
- クラス名にはフルスペルの英単語を組み合わせて使うことで、そのクラスの役割を連想できるようにする。
- 複数の単語でクラス名が長くなりすぎる場合は省略語を容認する。
>良い例
SalesOrderSlip
AccountRecievableService
AccountReceivableAlartMsg
>悪い例
SOrder
AccRecSrv
日本語コメントに頼らずクラスの役割が読み取れるよう、命名に使用する単語に気を配ります。
9.★★抽象クラスの名前には「Abstract」をつける
- 抽象クラスのクラス名の先頭から末尾に「Abstract」を付ける
- 抽象クラスはPascal形式で命名し、抽象的な機能を連想できる名前にする。
>良い例
abstract class SlipAbstract{
:
}
abstract class AbstractSalesOrderController{
:
}
public class SalesOrderController extends AbstractSalesOrderController{
:
}
10.★★インタフェース名はクラス名に準ずる
-
インタフェースはPascal形式で命名する。
- 命名はそのインタフェースの目的を連想できる名前にします。
-
インタフェースを明確にするために、名前の先頭に大文字の「I」1文字を付けて区別する
- プレフィックスがある場合は小文字の「i」を入れる
>良い例
interface IDigitalCamera{
:
}
interface IAudioPlayer{
:
}
public class MobilePhone implements IDigitalCamera, IAudioPlayer {
:
}
Interface GCCiCalendar{
:
}
一般的にインタフェースの定義は、インタフェースを実装するクラスとの関係を意識する必要がありません。
インタフェースの定義で重要なのは、そのインタフェースの目的を簡潔に表すことです。
11.★例外クラス名の末尾に「Exception」を付ける
- 例外クラスを定義する際にはクラス名の末尾に「Exception」を付ける
- 例外クラス名はPascal形式で命名します。
>良い例
public class BusinessObjecrException extends Exception{
:
}
public class InventoryUpdateErrorException extends BusinessObjectException{
:
}
- テストクラスの末尾に「Test」を付ける
- テストクラスの名前はテスト対象のクラスの名前の末尾に「Test」を付けたものとします。
>良い例
SalesOrderSlipTest
>悪い例
TestSalesOrderSlip
1.4 メソッド
13.★★★メソッド名は目的のわかる名前にする。
- メソッドが実行したときになにが起こるのかわかる名前を付けます。
>良い例
public SalesOrderSlip createSalesOrderSlip(...){
:
}
public String toString(){
:
}
日本語 | 英語 | 省略後 |
---|---|---|
受注 | sales order | slord |
伝票 | slip | --- |
確定する | firm | --- |
換算する | convert | --- |
計算する | calculate | --- |
検索する | search | --- |
出荷する | ship | --- |
初期化する | initialize | init |
表示する | display | --- |
取り消す | cancel | --- |
引き当てる | reserve | --- |
変更する | change | --- |
報告する | report | --- |
予約する | book | --- |
~する | do | --- |
~になる | become | --- |
~に変換する | to | --- |
~の長さを返す | length | --- |
14.★★★メソッド名はCamel形式で記述する
-
メソッド名は一つ以上の英単語で命名
- 最初の単語を小文字とし、続く単語の先頭文字を大文字にした小文字ベースの記述をする。
-
また、各単語の前後にはアンダースコア「_」やハイフン「-」やドル記号「$」を使用しません
>良い例
public void updateSalesOrderSlip (...) {}
public SalesOrderDetail getSalesOrderDetail (...) {}
public double getAmount (...) {}
>悪い例
public void UpdateSalesOrderSlip (...) {}
public SalesOrderDetail getSalesOrderDtl (...) {}
public double get_amount (...) {}
15.★★★メソッドの役割の対称性を意識する。
- 役割や機能が正反対になったメソッドを定義する場合は、対称性を意識して命名する。
>良い例
addDetail
removeDetail
getFirstItem
getLastItem
--- | 対義語例 | --- |
---|---|---|
add/remove | insert/delete | get/set |
start/stop | begin/end | send/receive |
first/last | get/release | put/get |
up/down | show/hide | source/target |
open/close | lock/unlock | source/destination |
old/new | next/previous | increment/decrement |
16.★ゲッターメソッド名は「get+属性名」とする
- ゲッターメソッド名は「get+属性名」とします
- ただし、booleanの属性の場合、「booleanを返すメソッドはtrue/falseの識別がわかる名前にする」に従う
>良い例
public SalesOrderSlip getSalesOrderSlip () {
:
}
17.★セッターメソッド名は「set+属性名」とする
-
セッターメソッド名は「set+属性名」とする
-
自動生成などの影響により引数の名前とフィールド名の一致が避けられない場合、「this」を付けます
>良い例
public void setSalesOrderSlip(SalesOrderSlip slip){
:
salesOrderSlip = slip;
}
public void setCustomerName(String customerName){
:
this.customerName = customerName;
}
18.★booleanを返すメソッドはtrue/falseの識別がわかる名前にする
-
メソッド名の先頭単語に常套句を使いboolean型のメソッドであることが連想できるようにします。
- booleanの返すメソッドは「is +形容詞」「can+動詞」「has+過去分詞」「三単現動詞」「三単現動詞+名詞」
-
逆にbooleanを返さないメソッドの名前の先頭に、is、can、has、を使うのは不適切。
>良い例
boolean isEmpty()
boolean canRemove()
boolean hasChanged()
boolean exists()
boolean existsStock()
>悪い例
//これはチェックか?という意味のメソッドになってしまう
boolean isCheck()
//セッターが返すbooleanの値の意味が不明瞭である。
boolean setAmount(...)
1.5 変数・定数
19.★★★変数には意味のある名前をつける
-
変数には1つの役割を与え、その役割を表す名前を付けます。
- フィールドの(インスタンス変数、クラス変数)の命名には、そのフィールドの役割を表す名前を付けます。
-
フィールド名とローカル変数名が衝突しないようにする。
-
ただしローカル変数には例外的に省略後や抽象名が使える。
- ストリームの名前
- inputStream,inStream,outputStream,outStream,ioStrem等
- for分で使用するループカウンタやイテレータの名前
- 慣習にならいi,j,kという1文字の変数名が使える
- catch節や6文で使用する例外オブジェクトの名前
- 慣習にならいeという1文字の変数名が使える。
- ストリームの名前
>良い例
//クラス名を含んだローカル変数
Customer deliveryCustomer;
//クラス名の一部を含んだローカル変数
ContractPriceDecisionService priceService;
:
//クラス名に等しいローカル変数名の例
SalesDetail salesDetail = createSalesDetail(...);
//インスタンス変数名の例
amountSubtotal = 0.0;
:
//数値型のローカル変数名の例
double unitPrice = priceService.getPrice(deliveryCustomer, item);
double cost = unitPrice * quantity;
salesDetail.setAmount(cost);
amountSubtotal += cost;
>悪い例
//役割を明示しないローカル変数
SalesDetail object = createSalesDetail(...);
:
double unitPrice = priceService.getPrice(deliveryCustomer, item);
//数値型のローカル変数numに短歌*数量を代入
double num = unitPrice * quantity;
//amoutというフィールドを持つobjectに金額を設定する
object.setAmount(num);
amountSubtotal += num;
:
//numに税額を代入
num = amount.Subtotal * taxRate;
if(num < deliveryCustomer.getSalesLimitValue()){
:
}
20.★★★変数名はCamel形式で記述する
- 変数名は1個以上の英単語で命名します。
- 最初の単語をすべて小文字とし、複数の単語をつなげるときには各単語を大文字にする。
>良い例
double cost = 0.0;
String sqlName; // GPS, SQL = lower case!
String gpsCommand;
>悪い例
double c = 0.0;
double uPrice;
String sQLName;
String GPSCommand;
最初の単語を小文字とし、続く単語の各先頭文字を大文字にする表記を「Camel形式」といいます。
Camel形式は「LowerCamel形式(LCC)」ともいいます
Camel形式での変数名表記はJavaの一般的なルール
21.★boolean型の変数はtrue/falseの識別がわかる名前にする
- boolean型の変数の名前にはtrueの事象を使います。
- boolean以外の変数にis,can,hasを使うのは不適切
>良い例
boolean isEmpty;
boolean canRemove;
boolean hasChanged;
boolean exists;
boolean existsStock;
22.GUIコンポーネントの命名にはコンポーネントの型を付加する
- GUIのコンポーネントを取り込んでアプリケーションで使用する場合、コンポーネント型の変数名の末尾はコンポーネント名とします。
>良い例
List customerList = new List(...);
Button cancelButton = new Button(...);
Menu fileMenu = new Menu(...);
MenuItem saveFileMEnuITem = new MenuItem(...);
23.★★引数名とフィールド名が同じになることを回避する。
-
メソッドの引数の名前はローカル変数の命名規約に従います。
-
引数には役割を表す名前を付ける
- フィールドとの衝突しないように引数の方の命名を工夫する。
>良い例1
private String itemCode;
private int quantity;
public void reserveStock(String anItemCode, int aQuantity){
itemCode = anItemCode;
quantity = aQuantity;
}
>良い例2
private String itemCode;
private int quantity;
public void reserveStock(String anItemCode, int quantity){
this.itemCode = anItemCode; //このような自動生成併用ケースでの特別な使い方として許容する。
this.quantity = aQuantity;
}
>悪い例
private String itemCode;
pricate int quantity;
public void reserveStock(String str, int quantity){
intemCode = str;
quantity = quantity;
:
}
メソッドの引数の名前はローカル変数の命名規約に従い、その役割を表す名前をつけます。
引数名は、単純に型や形式を表すだけの名前(number,num,string,str,list,map,tableなど)にはしません
24.★★定数名は「_」で区切った大文字表記とする。
- 定数変数であることが一目でわかるようにすべて大文字で記述します。
- 名前が複数の単語で構成される場合は単語間をアンダースコア「_」で区切る。
>良い例
public SalesSlip{
public static final String SLIP_NAME = "発注伝票";
}
interface IColoredPanel{
int SERIOUS_COLOR = 0xFF1010;
int WARNING_COLOR = 0x1010FF;
public void changeColor(String panelStatus);
}
>悪い例
public SalesSlip{
public static final String SlipName = "発注伝票";
}
interface IColoredPanel{
int SeriousColor = 0xFF1010;
int WarningColor = 0x1010FF;
public void changeColor(String panelStatus);
}
定数はプログラム宙に文字列リテラルや数値リテラルが直接コーディングされることによる可読性や保守性の低下を解消するために、使用が推奨されています。
同じ文字列リテラル(ダブルクォート「""」で囲んだ文字列)は可読性が低下するので定数を用いて書くようにする。
>リテラルの乱用
if(inputString.equals("#start") && processMode == 1){
:
}
if(!inputString.equals("#start") && processMode == 2){
:
}
:
if(!inputString.equals("#start") && processMode == 0){
:
}
同じようなリテラルが使われているため定数を適用してプログラムを修正する。
>定数の適用
private static final String START_COMMAND = "#start";
private static final int INITIAL_MODE = 0;
private static final int EDIT_MODE = 1;
private static final int DRIVE_MODE = 2;
if(inputString.equals(START_COMMAND) && processMode == EDIT_MODE){
:
}
if(!inputString.equals(START_COMMAND) && processMode == DRIVE_MODE){
:
}
:
if(!inputString.equals(START_COMMAND) && processMode == INITIAL_MODE){
:
}
2 コーディングに関する規約
2.1 全般
25.★★1つのクラスは1つのソースファイルで定義する
- 1つのソースファイルにはクラスを1つだけ定義する
- クラス定義のソースファイル名はPascal形式のままクラスと同じ名前にします
>良い例
SalesOrderSlip.java
~~~~~~~~~~~~
public class SalesOrderSlip{
:
}
>悪い例
SalesOeder.java
~~~~~~~~~~~~
public class SalesOrderSlip{
:
}
26.推奨されないAPIを使用しない
- Javaのリファレンスマニュアルで「推奨されていません」と記載されているAPIは使用しない
- 英語だと「Deprecated」と注釈されているAPIがある
27.使われないコードは書かない
- 使われていないprivateメソッドやローカル変数は、プログラム中に放置せず、消去する
- 未然にプログラムバグを防ぐ、可読性低下を防ぐため
28.★クラスやメソッドのアクセス修飾子の宣言は適切な権限で行う
-
public,protected,private,およびアクセス修飾子なしの4種類の可視性を適切に使い分ける。
- オブジェクトのカプセル化を実現
-
public
- その継承階層に属さない外部のオブジェクトから呼ばれる必要のあるメソッドはpublicにします
-
protected
- クラス階層の中で下位のクラスからの呼び出される場合
- 同一クラス内で親メソッドから呼び出される子メソッドがある場合に、子メソッドをprotectedにする。
-
private
- 自クラスのメソッドからしか呼び出されない。
-
フィールドで宣言された変数は原則としてprivateにする
- 下位クラスへのインターフェースとして必要なものをprotectedとします。
原則としてpublicやアクセス修飾なしにはしない
- 定数フィールドで自クラス以外から参照されるものをpublicとする。
>良い例
public abstract class AbstractSlip{
:
}
public class OrderSlip extends AbstractSlip{
public static final String SLIP_NAME = "発注伝票";
private int detailCount = 0;
:
public int getDetailCount(){
:
}
}
-
慣れるまで
-
クラスはすべてpublicにする
-
他のオブジェクトから呼び出されるメソッドはpublicにする
-
同じクラス内でpublicなメソッドから呼び出されるだけのメソッドはprivateにする。
-
フィールドはすべてprivateにする
-
定数はすべてpublicにする。
-
アクセス修飾子の好ましい順番
-
- public
-
- protected
-
- private
-
- abstract
-
- static
-
- final
-
- transient
-
- volatile
-
- synchronized
-
- native
-
- strictfp
-
-
フィールドの定義順序
- クラス変数→インスタンス変数
-
アクセス修飾の定義順序
- public→protected→アクセス修飾子なし→private(可視性の強さの順) -
メソッドの定義順序
- 基本は、機能ごと
- コンストラクタ
- クラスメソッド
- クラスの機能を象徴するメソッド
- 処理の順序性に従って並べる
- 初期化→設定→チェック→確定
- 役割の対称性のあるメソッド同士は並べて定義
- オーバーロードの関係にあるメソッド同士は並べて定義
- 同じフィールドに作用するメソッド同士は並べて定義
- add, remove, reverse, clear
- リファクタリングによって分割したメソッド同士は近くに並べる
- クラス内のユーティリティメソッドは最後の方にまとめて記述する
- 基本は、機能ごと
- メソッド定義とメソッド定義の間に空行を入れる。
- メソッド定義とメソッド定義の間に空行を1行入れる
- コメントアウトされている場合その次に空行を入れる
>良い例
protected abstract boolean checkFileAttribute(File file)
throws ProjectDashboardException;
/**
/* ファイルのアトリビュートのデータを削除する
/* @param file ファイルパス
*/
protected abstract void deleteFileAttribute(File file)
throws ProjectDashboardException;
/**
/* ファイルパスからベースとなる文字列を削除
/* @param file
/* ファイルパス
/* ベース削除するパス
/* @return 加工後の文字列
/* @throws ProjectDashboardException ファイルパス加工時の異常
*/
private String replacePath(File filr, File removePath)
throws ProjectDashboardException{
:
return afterString;
}
>悪い例
protected abstract boolean checkFileAttribute(File file) throws ProjectDashboardException;
protected abstract void deleteFileAttribute(File file) throws ProjectDashboardException;
private String replacePath(File filr, File removePath) throws ProjectDashboardException{
:
return afterString;
}
30.★プリミティブ型と参照型の違いを認識する
-
変数の型はプリミティブ型と参照型に大別される。
- これらの値の保持や仕方や初期化の振る舞いが異なる
-
メソッドのパラメーターとして渡される引数にもプリミティブ型と参照型がある。
- プリミティブ型
- byte,short,int,long,float,double,char,boolean
- 参照型
- クラス型、インタフェース型、配列型(これらを総省してオブジェクト型と呼ぶこともある)
- プリミティブ型
メソッドの引数は入力パラメーター。引数に対して値の代入や属性の更新はしない
>プリミティブ型の挙動の例
import java.awt.Point;
:
Point point = new Point(100,100);
putStone(point, 10);
putStone(point, 20);
moveStone(point, 15,15,10);
moveStone(point, 60, 30, 20);
:
~~~~~~~~~~~~~~~~~
void putStone(int posX, int posY, int size) {
Point point = new Point(posX, posY);
drawStone(point, size);
}
void moveStone(int posX, int posY, int deltaX, int deltaX,int size) {
posX = posX + deltaX;
posY = posY + deltaY;
Point point = new Point(posX, posY);
drawStone(point, size);
}
>参照型の挙動の例
import java.awt.Point;
:
Point point = new Point(100,100);
putStone(point, 10);
putStone(point, 20);
moveStone(point, 15,15,10);
moveStone(point, 60, 30, 20);
:
~~~~~~~~~~~~~~~~~
void putStone(Point location, int size){
drawStone(location, size);
}
void moveStone(Point location, int deltaX, int deltaY, int size){
location.x = location.x + deltaX;
location.y = location.y + deltaY;
drawStone(location, size);
}
31.★ラッパークラスよりプリミティブ型を使う
-
ラッパークラス型(Integer,Double,Boolean)よりプリミティブ型(int,double,boolean)を使う
- コレクション要素を使う場合はラッパークラス型を使う
-
ラッパークラスはオブジェクト値としてnullになる
- Null PointExcepionがスローされる可能性
-
「==」演算で同値比較ができません。
2.2 スタイル
32.★★クラス定義の記述順序を守る
- ソースファイルの中に構成要素の記述順序に一貫性を持たせる可読性が高まる
- ソースファイル開始コメント
- package文
- import文
- クラス、インタフェースのドキュメンテーション
- class,Interfaceの宣言
- staticなフィールド(クラス変数)の宣言
- static以外のフィールド(インスタンス変数)の宣言
- コンストラクト定義
- メソッド定義
1つのソースファイルの最大行数を基底していませんが、他の規約ではその最大値を500行、600行、2000行程度に制限しています。
33.★★110行を超える行は改行または文を分割する
-
開発プロジェクトで指定した桁位置を超えるような長い行をコーディングしません。
-
コードの右側「//」で開始する行末コメントは記述しない
-
Javadoc用のコメント分は80桁いないに収まるようにする。
34.★★行の途中での改行は、カンマの後、演算子の前、節(予約語)の前とする
-
行が長くてスクロールが必要になるときは、行の途中で改行して読みやすくする。
-
クラスやメソッドの宣言行では、まずextends、implements、throw節の前で改行し、次にカンマの後ろで改行します。
-
改行後の行の先頭は4桁分インデント(字下げ)します。
>良い例
private Map<String, CCData> createDataBox(File eBaseDirectory)
throws ProjectDashboardException{
:
ClassifiedCategory classfiedCategory = new ClassfiedCategory(aBaseDirectory,
projectName, ClassfiedCategory.BuSINESS_TXT,Function.CheckStyle);
try{
CCData sourceCode = null;
while(reader.hasNext()){
int xmlType = reader.next();
//Checkstyle実行結果ファイルを読み込み、タグや属性の値を見る
if (xmlType == XMLStreamReader.START_ELEMENT
&& reader.getLocalName().equals(FILE)) {
//Fileタグの処理(ソースコード単位の読み込み開始)
File sourceCodeFile = new File(reader.getAttributeValue(0));
String sourceCodePath = replacePath(sourceCodeFile, getTempPath());
}
}
}
int hashCode = new MyHashCodeBuilder(12,23).append(projectName)
.append(sourceCodePath).append(versionNumber).toHashCode();
}
35.★★クラスとメソッドの宣言行およびブロック開始行の末尾に「{」を記述する
-
クラスの宣言の行の末尾に「{」を記述します。
-
if,for,while,do,switchなどの制御文なども同様に「{」記述
-
「{」の前に半角の空行文字を1文字いれる。
原則として「{」の直前では改行しない
>良い例
public class FileUtility{
:
}
>悪い例
public class FileUtility
{
:
}
36.★★「{」の後ろにステートメントを記述しない
- 「{」は行の末尾にしか記述しないため、ステートメント(文)を記述しない
- どんなに短い文であっても「{」で必ず改行してから事業から記述する
>良い例
if (containsKey(source)) {
type = ORIGINAL_FILE_TYPE;
:
}
>悪い例
if (containsKey(source)) { type = ORIGINAL_FILE_TYPE;
:
}
37.★★インデントは半角の空白文字を使い4桁分とする
- 開発プロジェクトで特に取り決めがない限り、インデントは半角の空白文字で4桁ずつとします。
- インデントにはタブ文字(TAB)やセミコロン「;」を使用しない
使用するテキストエディタやプリンタによってタブ位置の設定が異なります。
インデントにタブ文字や空白文字を混在させると、別の環境でソースコードを見たときにインデントが崩れてしまう場合があります。
38.★★ブロックの開始行と終了行のインデントを揃える
- ブロック開始行の先頭と、ブロックの終了位置の「}」のインデントを揃えます。
- ブロックごとに改行すると可読性が低下するため。
>悪い例
whilr(!isEmpty()){
if (containsKey(itemName)){
:
} else
if{
:
}
}
39.★★ブロックの内部のインデントを揃える
- ブロックの中にある各行の先頭の桁位置を揃え、インデントを整えます。
40.★無駄な空行は入れず意味のある切れ目で入れる
-
メソッドの定義本体内でステートメント間に空行によって可読性があがる
- ただし、空行を入れすぎると間延びが起こってしまう。
- 空行には必ず意図があることを意識する。
- ただし、空行を入れすぎると間延びが起こってしまう。
-
package文とimport文の間は1行空ける。
-
import文の最後とclass宣言との間はは1行空ける
-
if文、for文、while文、switch文、try文の直前に空行は不要。
- 意味のある切れ目として重要なら空行ではなくコメント文を書く。
41.★★1行に2つ以上のステートメントを書かない
- 1行に複数の文(ステートメント)を横に並べて記述しない。
>良い例
index[0] = 10;
index[1] = 19;
index[2] = 24;
>悪い例
index[0] = 10; index[1] = 19; index[2] = 24;
42.★比較演算子は「<」か「<=」を使う
- 比較演算子には「<」か「<=」を使う
- 「>」と「>=」は使わない
if文やfor文やwhile文で記述する条件式で用いる不等号は「<」か「<=」に統一する
不等号を含んだ複数の条件氏がある倫理結合プログラムを読む場合に不等号の右辺値が大きい時がtrueなのか、左辺値が大きいときがtrueなのか、条件式ごとに向きがばらばらだと読み誤りを起こす可能性が大きくなります。
43.オートボクシングを使用しない
- ラッパークラス型のオブジェクトに対する値の設定では、オートボクシングを使用しません
- if文やwhile文などの条件節では、自動的なアンボクシングを使用しません
プリミティブ型変数をラッパークラス型のオブジェクトに代入しない!
>良い例
List<Double> divisionList = new ArrayList<Double>
divisionList.add(100.0);
divisionList.add(200.0);
:
double subAmount = 0.0;
:
double totalAmount = price * count + subAmount;
Double divisionObj = iterator.next();
if(divisionObj != null){
double division = divisionObj;
if(totalAmount == divition){
:
}
}
>悪い例1
double subAmount = 0.0;
:
double totalAmount - price * count + subAmount;
Double division = iterator.next();
if(division != null && totalAmount == divition){
:
}
>悪い例2
long megaSum1(){
Long sum = 0L;
for(int i=0; i<2000000; i++){
sum = sum + i;
}
return sum;
}
long megaSum2(){
Long sum = 0L;
for(int i=0; i<2000000; i++){
sum = sum + i;
}
return sum;
}
44.★★カンマ、セミコロン、コロンの後ろや演算子の前後に空白を入れる
-
カンマ、セミコロン、コロンの後ろに空白を1文字挿入する。
- 複数のつーつが重複して適用され空白が2個以上になる場合は1個の空白で十分。
-
空白には細かいルールが設定されているが、IDEのオートフォーマット機能で機械的には揃えることができる。
2.3 クラス定義
45.継承させたくないクラスにはfinal宣言をする
- 継承させたくないクラスには宣言時にfinal修飾子を付ける。
- 宣言されたクラスに対してはサブクラスは定義できない。
>良い例
public final class OrderSlip extends AbstrctSlip {
public static final String SLIP_NAME = "発注伝票";
private int detailCount = 0;
:
public int getDetailCount() {
:
}
}
46.クラスにtoStringメソッドを装備する
- クラスの定義時に、toStringメソッドの実装が可能なら、実装する。
- System.out.println()で見えるようにできるため
47.★★メソッドのないインタフェースを定義せず定数クラスを使う
- 定数だけが定義されたインタフェースを作らない
- 定数を定義するだけなら、定数クラスを作り、そこから他のクラスが定数を参照する
- 巨大な定数クラスは作らない。定数クラスが巨大になりそうなときは複数の定数クラスをつくる。
- 定数を定義するだけなら、定数クラスを作り、そこから他のクラスが定数を参照する
良い例
package constant;
class FDConstants{
public static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
:
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import constant.FDConstants.DEFAULT_DATE_FORMAT;
class FDOrderPage{
public FDOrderPage(){
String defaultDateFormat = FDConstants.DEFAULT_DATE_FORMAT;
:
}
}
48.★定数クラスにはstaticイニシャライザを使う
- 定数クラスのstaticメンバ変数を初期化する手段としてstaticイニシャライザを使う
>良い例
class FDConstants{
public static final String DEFAULT_DATE_FORMAT;
:
static{
:
DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
}
}
2.4 メソッド定義
49.★★メソッドの最大行数は150行とする
- メソッドは150行以下で書くように設計する。
- 超える場合は子メソッドに処理の一部を委譲すつような構造化を行う(リファクタリング)
50.★★循環的複雑度の上限を19とする
-
メソッドのロジックの循環的複雑度の目安は以下のようになる
- 循環的複雑度が10以下ならプログラムは読みやすく、単体テストも容易
- 循環的複雑度が11~19ならリファクタリングの要否のレビューをする
- 循環的複雑度が20委譲ならリファクタリングを実施し、数値を下げます
- 循環的複雑度が50を超えた場合、テストは不能となる
-
循環的複雑度はCheckstyleでチェックすることができます。
51.オーバーライドさせたくないメソッドはfinal宣言をする
- メソッドをfinal宣言することで、そのクラスのサブクラスでオーバーライドが定義できなくなる。
メソッドがオーバーライドされないことが明示されるので可読性が上がる。
メソッドがオーバーライドされないことが、コンパイラに通知されるので、コードの最適化がより適切に行われる
>良い例
public class OrderSlip extends AbstractSlip{
public static final String SLIP_NAME = "発注伝票";
private int detailCount = 0;
:
public final int getDetailCount(){
:
}
}
52.★メソッドの引数の順序には根拠がある
-
引数はメソッドの振る舞いの実現に必要なインプットのみとします。
- 内部で参照されないパラメーターは渡さない
-
引数の順序規約の基本パターンは以下の通り
- メソッドに重要なインプットを先頭パラメータにする。
- オブジェクト形の引数をプリミティブ型の引数よりも先に並べる
- 業務系のオブジェクトを非業務系のオブジェクトよりも先に並べる
- 複数のパラメーターの場合、並べて配置する
- 対称性のあるメソッド同士、関連性のあるメソッド同士はパラメーターの並べ方を揃える
- テーブルの入出力に関連する場合はキーの順番、カラムの順番に合わせる
- 日常に関連するものはその慣習に合わせて並べる
メソッドの引数の順序に一定の秩序を持たせることでプログラムの可読性が向上します。
53.★配列やコレクションを返すメソッドではnullを返さない
- 配列を返すメソッドではnullを返さずに0を返すようにする
- コレクションを返すメソッドでも同様に
>良い例
public LinkedList<String> getMetricsList(String projectName)
throws ProjectDashboardException{
:
LinkedLis<String> metricsList = new LinkedLis<String>();
// 処理対象がないときは復帰する
if(!existsProperty(key, projectPathMap.get(projectName))){
return metricsList.emptyList();
}
metricsList.add(Function.CheckStyle.getName());
return metrixList;
}
>悪い例
public LinkedList<String> getMetricsList(String projectName)
throws ProjectDashboardException{
:
// 処理対象がないときは復帰する
if(!existsProperty(key, projectPathMap.get(projectName))){
return null;
}
LinkedLis<String> metricsList = new LinkedLis<String>();
:
metricsList.add(Function.CheckStyle.getName());
return metrixList;
}
配列やコレクションを返すメソッドの呼び出しでは状況によってnullが返されると呼び出しもとでnullチェックの実装が必要になります。
54.★★引数の数は少な目にする
-
メソッドの引数の数は上限を10個とする(256以上でエラーがでる)
- ただし、コンストラクションの引数の数はこの限りではありません
-
引数が上限値以下の数であっても、同じ型の引数が多数並ぶことを避ける
-
使われない引数は渡さない
-
引数を減らすためには
- Beanを使おう
- 減らすためにCollectionやMapに格納するのは非推奨のため避ける
- カテゴリごとに配列に入れられるかどうか
- メソッドごとに分けられるかどうか
- Beanを使おう
55.★引数の正当性を検査する
-
publicメソッドとコンストラクタの引数は、その正当性を検査してから内部の処理に引き継ぐ
- インデックス値の場合、負でないことをチェック。あるいは上限、下限のチェック
- オブジェクトの参照である場合は、nullでないことをチェック
- 複数のパラメータを保持したパラメータ専用クラスのインスタンスで、自己の検査メソッドを有する場合は、その検査メソッドを呼び出してチェックする。
-
引数のチェックの結果、正当性が否定された場合は、例外をスローする。
-
protectedメソッド、privateメソッドの場合は、呼び出し元を限定できるので、冗長の検査は行わない。
>良い例1
/**
/* 指定されたパラメータでViolationオブジェクトを構築します
/* @param aClassID
/* クラスIDは0以外の整数値
/* @param aMesurementDay
/* 測定日はdate型で生成したインスタンス
/* @param aSerialNumber
/* シリアル番号
/* @throws ProjectDashboardException
/* 初期化引数の値の不備に対する例外
*/
public Violation(int aClassID, Date aMeasurementDay, int aLineNumber,
int aSerialNumber) throws ProjectDashboardException {
if((0 != aClassID) && (aMeasurementDay == null)) {
throw new ProjectDashboardException(Severity.ERROR, "0009", "Violation");
}
classID = aClassID;
:
}
>良い例2
/**
/* プロジェクトデータにドキュメント情報を設定します
/* @param xssfWorkbook
/* Excel読み込み部品はXSSFWorkbook型で生成したインスタンス
/* @param dataBox
/* データ保持部品はDataBox型で生成したインスタンス
/* @param sheetName
/* シート名は1文字以上の文字列
/* @throws ProjectDashboardException
/* シート取得時の異常
/*
**/
private void createDocument(XSSFWorkbook xssfWorkbook, Databox databox,
String sheetName) throws ProjectDashboardException{
assert cssfWorkbook != null;
assert dataBox != null;
assert sheetName != null;
assert 0 < sheetName.length();
:
}
56.クラスメソッドを実行するときはクラス名を使って呼び出す
- クラスメソッドを実行するときはクラス名を使って呼び出しを記述する
- 記述の形式は「クラス名.メソッド名(引数)」となる
- 「インスタンス.メソッド名(引数)」のように記述しない
>良い例
private DataBox firstLaunch () throws ProjectDashboardException {
//実行結果を格納するDataBox
DataBox latestDataBox = null;
//対称のドキュメントが存在するか
if (FileUtility.existsDocument(getTempDir())){
runDocumentTool();
latestDataBox = createDataBox();
} else {}
}
>悪い例
private DataBox firstLaunch () throws ProjectDashboardException {
//実行結果を格納するDataBox
DataBox latestDataBox = null;
FileUtility fileUtil = new FileUtility;
//対称のドキュメントが存在するか
if (fileUtil.existsDocument(getTempDir())){
runDocumentTool();
latestDataBox = createDataBox();
} else {}
}
2.5 変数・定数
57.★定数はstatic fainalを宣言する
-
定数はフィールドで実現します。
- staticとfinalで修飾
-
定数に対してセッターは定義できない(固定されているため)
-
定数の場合のみフィールドでpublicを使用することは可能
>良い例
//デフォルト日付フォーマット
private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHmmss";
58.★リテラルは原則として使わず定数を使う
-
final以外の変数の初期化で、0(ゼロ)、""(ヌル文字列)以外の値を使う際に、数値リテラルや文字列リテラルを使用しない
-
以下の場合以外は数値リテラルや文字列リテラルは使用しない
- 代入式
- 演算式
- 条件式での比較の対称
- メソッドの引数
- switch分のcase値に0,""(ヌル文字列)を使う
-
-1,0,+1,""(ヌル文字列),null,true,falseは積極的に意味づけされていない場合リテラルではない
- 百分率の計算で使う100を記述し、リテラルとはみなされない
>良い例
private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
:
String beforeDate = manager.getDate(DEFAULT_DATE_FORMAT);
>悪い例
String beforeDate = manager.getDate("yyyyMMddHHmmss");
リテラルはプログラムの可読性、保守性を損ねる原因として可能な限り使用を回避します。
Javaの開発ではリテラルを使う代わりに定数の使用を推奨しています
定数はfinalで修飾した変数で実装します。
【何らかのコード体系の一覧をリテラル定数化するときの注意事項】
- 何らかの定数化するときに、リテラルの中身を定数の名前に割り当てるだけでは意味がない
- メッセージ文などのようやくを定数名にするように
>良い例
- メッセージ文などのようやくを定数名にするように
static final String MSG_FILE_NOT_FOUND = "CSS001E";
>悪い例
static final String MSG_ID_001 = "CSS0001E";
59.★★配列の宣言は型名に「[]」を付けて行う
- 配列を宣言するときは、型名に「[]」を付けて宣言を行う
- 変数名に「[]」を付けないようにする
>良い例
String[] dateArray = dateCombo.getItems();
int[] totalCounter = {0,0,0,0};
>悪い例
String dateArray[] = dateCombo.getItems();
int totalCounter[] = {0,0,0,0};
60.★配列は宣言時に大きさを明確にする
- 配列は大きさが明確になるように
- 宣言時に大きさを明確にしなかった場合は、初期化によって大きさを明確に。
>良い例
int[] totalCounter = {0,0,0,0};
int[] subtotalCounter = new int[5];
>大きさを明確にできない例
String[] dateArray = dateCombo.getItems();
61.★2次元以上の配列を宣言しない
-
配列の使用は原則として1次元のものだけにする(可読性を低下させないため)
- 多次元のデータを扱う場合、1次元の配列とArrayListやMapとの組み合わせで代用できないか検討する
-
数学的に行列を扱う場合、CSVや表計算による2次元データなど、行番号、列番号で要素を取り扱う場合に、多次元配列を使うことがあります。
>良い例
HashMap<String, int[]> eventName = (HashMap<String, int[]>) table.getData();
int[] value = (int[]); eventName.get(name);
>例外的に認められる行列形式のデータ
int[][] counterMatrix = {
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
}
多次元配列の使用は可読性の悪化要因になると考えてます。
極力コレクションを扱うようにする
62.配列のコピーにはarraycopyメソッドを使用する
- 配列のコピーにはSystem.arraycopy()メソッドを使う。
>良い例
String[] brand = {"ASAHI", "KIRIN", "SUNTORY"};
:
int lengh = brand.length;
String[] brandCopy = new String[length];
System.arraycopy(brand, 0, brandCopy, 0, length);
>良い例2
String[] brand = {"ASAHI", "KIRIN", "SUNTORY"};
:
String[] brandCopy2 = (String[])brand.clone();
>良い例3
String[] brand = {"ASAHI", "KIRIN", "SUNTORY"};
:
int length = brand.length;
String[] brandCopy3 = Arrays.copyof(brand, length);
>悪い例
String[] brand = {"ASAHI", "KIRIN", "SUNTORY"};
:
int length = brand.length;
String[] brand = new String[length];
for(i = 0;i<length; i++){
brandCopy[i] = brand[i];
}
-
参照のコピーを行うことをシャローコピーという
-
要素のオブジェクトのコピーを新たに作りながら配列を複製することをディープコピーという
>ディープコピーの例
int length = numberList.length;
BigDecimal[] numberCopy = new BigDecimal[length];
for(int i=0; i<length; i++){
numberCopy[i] = new BigDecimal(numberList[i].toPlainString());
}
63.インスタンス変数は必ず初期化する
- インスタンスの初期化には以下のような方法がある
- コンストラクタの中で初期化する(もっとも優先される初期化方法)
- インスタンス変数の宣言時に初期化する
- イニシャライザで初期化する
- ゲッターにより初めて値が参照されるときに初期化する
>良い例
public class DRData implements Data, Serializable{
private String name = "";
private Date date;
private LinkedList<Date> radioDateList = new LinkedList<Date>();
private List<SheetDate> sheetList;
{
for (int i=0; i <= 5; i++){
Date graphDate = GraphUnil.getGraphDateWeek(i);
if(graphDate != null){
radioDateList.add(graphDate);
}
}
}
public DRDate(String aName, Date aDate){
name = aName;
date = aDate;
}
public List<SheetDate> getSheetList(){
if(sheetList == null){
sheetList = selectSheetList();
}
return sheetList;
}
}
型のカテゴリ | 初期値 | 型の例 |
---|---|---|
整数 | 0 | int short long |
浮動小数点数 | 0.0 | double float |
char 型 | '¥u0000' | char |
boolean 型 | false | boolean |
参照型 | null | String 配列 コレクション 任意のクラス |
- コンストラクタの中で初期化する
メリット | デメリット |
---|---|
スレッドセーフである。インスタンスごと、引数を使った初期化ができる。コレクションオブジェクトの要素の初期化ができる | 変数の宣言と初期化を離れたところに記述するので、実装時の「初期化忘れ」が起きやすい複数のコンストラクトが存在すると、指揮下する変数と指揮下しない変数の区別が不揃いになりやすい。 |
- インスタンス変数の宣言時に初期化する
メリット | デメリット |
---|---|
スレッドセーフである。インスタンスの生成が速い、インスタンスの生成と同時に初期化できる | インスタンスごとの異なる初期化ができない。初期化の順序が宣言順に固定である。コレクションオブジェクトの要素の初期化ができない。 |
- イニシャライザで初期化する
メリット | デメリット |
---|---|
スレッドセーフである。コンストラクトより先に実行されるので書くコンストラクトに共通な初期化を記述できる。初期化の順位を任意に記述できる。コレクションオブジェクトの要素の初期化ができる。無名のインナークラスの初期化に使える。 | どのコンストラクトが実行される場合でも先にイニシャライザが実行されるので、性能劣化に対する注意が必要。 |
- ゲッターにより初めて値が参照されるときに初期化する。
メリット | デメリット |
---|---|
値が必要になるまで初期化しないので、ディスクアクセスを伴うような処理時間の長い初期化を必要最低限の頻度にできる | スレッドセーフに実装することが手間になる。同じクラスの他のメソッドに対してもフィールドを隠ぺいする必要が生じてしまう |
64.★インスタンス変数はprivateで宣言する
-
インスタンス変数の宣言時にはアクセス修飾子をprivateにする。
- ただし、static以外のフィールド
-
派生クラスでのアクセッサ(セッター、ゲッター)のオーバーライドを許可する場合に、関連するインスタンス変数をprotectedにする。
オブジェクトが部品として、壊れず、決められた通りに動作するためには、インスタンス変数は他のオブジェクトからは隠蔽しなくてはならない。
このような内部状態に対して外部からのアクセスを制限して、堅牢な構造を持つことを「カプセル化」といいます。
- むやみにアクセッサ(セッター、ゲッター)を定義しない
-
フィールドの目的に則って判断し、アクセッサを意味のあるメソッドにする。
-
ゲッターメソッドの可視性をpublicにし、セッターメソッドの可視性をprotectedにする場合がある。
>良い例
public class Profile {
private String zipCode = "";
private String addressCity = "";
private String addressNumber = "";
:
public void setAddressSet(String aZipCode, String addressNum){
:
}
}
>悪い例
public class Profile {
private String zipCode = "";
private String addressCity = "";
private String addressNumber = "";
:
public void setZipCode(String aZipCode){
:
}
public void setAddressCity(String anAddressCity){
:
}
public void setAddressNumber(String addressNum){
:
}
}
全てをセッター、ゲッターを定義したらカプセル化の意味がありません。
目的に沿った定義の仕方をしましょう。
66.クラス変数にpublic static final宣言した配列を利用しない
- public static final宣言した配列は用いらない
>良い例
private static final String[] DAY_OF_WEEK_STR = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
public static final List DAY_OF_WEEK = Collections.unmodifiableList(Arrays.asList(DAY_OF_WEEK_STR));
>悪い例
private static final String[] DAY_OF_WEEK_STR = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
67.★クラス変数はクラス名を使ってアクセスする
-
クラス変数をアクセスするときはクラス名を使って参照や代入を記述する
-
自クラスのクラス変数を使用する場合はクラス名を省略する
>良い例
public class GraphParts {
:
public static final List DAY_OF_WEEK = Collections.unmodifiableList(Arrays.asList(DAY_OF_WEEK_STR));
:
~~~~~~~~~~~~~~~~~~~~~~~~~~
public class DisplayGraph{
:
public void draw(){
:
String dayOfWeek = GraphParts.DAY_OF_WEEK.get(i);
:
}
}
}
>悪い例
public class DisplayGraph{
:
public void draw(){
GraphParts graphParts = new GraphParts();
:
String dayOfWeek = graphParts.DAY_OF_WEEK.get(i);
:
}
}
クラス変数は「インスタンス.フィールド名」のように記述しても正しく扱えます。
クラス変数の記述個所では、クラス名を使うことでクラス変数であることを明瞭化し。プログラムの可読性を高める。
68.★★ローカル変数名とフィールド名が同じになることを回避する
- ローカル変数の宣言では、そのクラスで定義済みのフィールドと同じ変数名を使わない
>悪い例
public class Profile{
private String zipCode = "";
private String addressCity = "";
:
public void setZipCode(String aZipCode){
String addressCity = AddressUtility.searchAddress(aZipCode);
:
this.addressCity = addressCity;
}
}
69.ローカル変数は安易に再利用しない
-
一度宣言したローカル変数を、複数の目的で使いまわさない
-
ただし、for文のカウンタ変数のi,j,kやイテレータに使用する変数iteratorについては再利用する場合がある
>良い例
List deliveryDateInput = getDateInput();
String yearStr = deliveryDateInput.get(1);
year = Integer.parseInt(yearStr);
>悪い例
List deliveryDateInput = getDateInput();
String year = deliveryDateInput.get(1);
year = Integer.parseInt(year);
ローカル変数には、省略語や抽象的な単語による命名が容認されています。
しかし、ローカル変数の使いまわしをすると、値のバリエーションが広がりプログラムの可読性を下げます。
70.★ローカル変数は使用する直前に初めて宣言と初期化を行う
-
ローカル変数は宣言と同時、あるいは宣言直後に初期化を行う
-
使用する直前で宣言と初期化をする
- ローカル変数を扱う場所は小さくすることによって可読性があがる。
-
例外として
- try-catch文のtryブロックでもcatchブロックでもtry-catch文の後方でも使われる場合、try文の手前で記述する
- if分やfor文のブロックの内側で値を設定し、そのブロックの外側で値の参照が必要なローカル変数は、このブロックの手前で宣言と初期化をする
>良い例
List deliveryDataInput = getDateInput();
String yearStr = deliveryDateInput.get(1);
>悪い例
List deliveryDataInput = getDateInput();
String yearStr;
yearStr = deliveryDateInput.get(1);
2.6 文字列操作
71.★更新される文字列にはStringBuilderを使用する
-
更新される文字列にはStringBuilder型で宣言する
- StringBuilder型はStringBuffer型と同じ使用方法
-
StringBuilderは高速
- ただしスレッドセーフではない
-
一般的には
- インスタンス変数にはStringBufferを使用する
- ローカル変数にはStringBuilderを使用する
>良い例1
public void insert(DBConnection connection) throws SQLException{
StringBuilder sql = new StringBuilder(1024);
sql.append("INSERT INTO STEPCOUNT VALUES (");
sql.append(classID);
sql.append(",");
sql.append(totalStep);
sql.append(",");
sql.append(totalCommentStep);
sql.append(",");
sql.append(totalJavadocStep);
sql.append(",");
sql.append(handwritingStep);
sql.append(",");
sql.append(handwritingSqlStep);
sql.append(")");
connecion.executeUpdate(sql.toString());
}
>良い例2
public void insert(DBConnection connection) throws SQLException {
String sql = "INSERT INTO STEPCOUNT VALUES ("
+ classID + ", " + totalStep + ", "
+ totalCommentStep + ", " + totalJavadocStep + ", "
+ handwritingStep + ", " + handwritingSqlStep
+ ")";
}
// "INSERT INTO STEPCOUNT VALUES (" と "," と ")"はインターンされるため、ガベージになると見なしません
>悪い例1
public void insert(DBConnection connection) throws SQLException{
String sql = "INSERT INTO STEPCOUNT VALUES (";
sql += classId + ",";
sql += totalStep + ",";
sql += totalCommentStep + ",";
sql += totalJavadocStep + ",";
sql += handwritingStep + ",";
sql += handwritingSqlStep + ")";
connecion.executeUpdate(sql);
}
>悪い例2
public void insert(DBConnection connection) throws SQLException{
StringBuilder sql = new StringBuilder(1024);
sql.append("INSERT INTO STEPCOUNT VALUES (");
sql.append(classId + ",");
sql.append(totalStep + ",");
sql.append(totalCommentStep + ",");
sql.append(totalJavadocStep + ",");
sql.append(handwritingStep + ",");
sql.append(handwritingSqlStep + ")");
connecion.executeUpdate(sql.toString());
}
StringBuilderは、インスタンスの生成時に、初期値の文字列に16文字分の余裕を加えたバッファを用意し、そこに文字列を保持します。
StringBuilderが保持する文字列を更新すると、バッファの領域が不足しない限り、同じバッファを使い続けて消費メモリーを節約します。
72.★更新されない文字列にはStringを使用する
-
更新が想定されない文字列はStringで宣言
- 値の設定と参照と破棄しか怒らない文字列のこと
-
文字列連結演算子(+)を使って、継ぎ足しを行わない
- ループの内側に含まれない個所での短い文字列の連結にはString型と文字列連結演算子(+)を使ってもok
-
StringBuffer型、StringBuilder型をStringに代入するには明示的な型変換をする
-
初期値について
- 後の処理の中で値が設定される場合はnull
- 文字列の代入や結合に使用し、値がないことを示す場合は""
- 設計上、Stringになにかしらの文字を入れる仕様の場合、プログラミングミス発見のためにnullにする
- NullPointExceptionのスローによって実行時にバグ検出ができるから。
- プリミティブ型とStringオブジェクトとの返還には変換メソッドを使う
-
int,doubleなどのプリミティブ型の数値をString型の文字列に変換するには、StringクラスのvalueOfメソッドを使用する
- String.valueOf();
-
String型の文字列で表記された数値をint,doubleなどのプリミティブ型に変換するには、IntegerクラスのparseIntメソッドやDoubleクラスのparseDoubleメソッドを使用する
- Integer.valueOf();
2.7 数値操作
74.誤差のない計算をするにはBigDecimalを使用する
-
double型を使った浮動小数点ではわずかながら計算誤差が生じる
- 誤差のない計算をする場合、BigDecimal型で計算をする
-
使用例
- 金銭の計算をする場合
- 外国為替
- 外貨(特に補助単位のある場合)
- 消費税(とくに内税額)
- 利息などを正確に計算したい場合
- 金銭の計算をする場合
-
BigDecimalを使っても循環少数が生じると誤差が出る
- 要求する制度に対して8種類の丸目モードを使い分けられる
>良い例1
public BigDecimal calculateTax5Percent(BigDecimal amount){
BigDecimal taxRate = new BigDecimal("0.05");
BigDecimal tax = amount.multiply(taxRate);
:
return tax;
}
doubuleは2進数に変換され計算し、また10進数にもどして表示するため、そこで誤差が生じる
75.★数値の制度に気を付ける
-
有効桁数に気を付ける
-
数値型の仕様一覧
|数値型|サイズ|値の範囲|有効桁数|
|:---|:---:|:---:|---:|
|short,Short|16ビット|-32768~+32767|4桁|
|int,Integer|32ビット|-2147483648~+2147483647|9桁|
|long,Long|64ビット|-9223372036854775808~+9223372036854775807|18桁|
|float,Float|32ビット|多すぎるため割愛|18桁|
|float,Float|32ビット|多すぎるため割愛|18桁|
>誤差発生の例
for(double point = 0.1; point <= 1000.0; point = point + 0.1){
drawMark(point);
}
>誤差を蓄積しない例
for(int pointBase = 1; pointBase <= 1000; pointBase++){
double point = pointBase / 10.0;
drawMark(point);
}
>誤差を丸める例
for (double point = 0.1; Math.round(point * 10*) <= 10000; point = point + 0.1){
drawMark(point);
}
76.4桁以上の数値リテラルには3桁ごとにアンダースコアを挿入する(JavaSE7以降)
- プログラムの中に数値リテラルが登場する場合、3桁ごとにアンダースコアを配置
>良い例
static long UPPER_LIMIT_VALUE = 80_000_000_000L;
>悪い例
static long UPPER_LIMIT_VALUE = 80_000_000_000L;
77.低精度なプリミティブ型にキャストしない
-
精度の高いプリミティブ型から精度の低いプリミティブ型にキャストしない
- 丸めや情報落ちやオーバーフロー/アンダーフローが起こり、もともと持っていた情報を失う可能性
-
例
- long型→int型にキャストでオーバーフローが起きる可能性
- long型やint型をfloatにキャストすると情報落ちが起きる可能性
- double型やfloat型をintにキャストするとオーバーフロー、アンダーフロー、丸め誤差が起きる可能性
- ただし、意図的な丸目を起こすために、double型やfloat型をintにキャストすることがある。
2.8 継承
78.スーパークラスのインスタンス変数をサブクラスで重複して定義しない
-
スーパークラス側のフィールドと同じ役割のフィールドを必要とするなら、スーパークラスのフィールドを継承して、サブクラス側でも使用する。
- 可視性がpublic,protected,修飾子なしの場合
-
スーパークラス側のフィールドの可視化がprivateで継承できない場合は、スーパークラスのフィールドをprotectedに変更する
>悪い例
public class GraphParts {
:
protected String GraphTitle = "";
:
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class CustomGraphParts extends GraphParts {
:
protected String GraphTitle = "";
:
}
79.スーパークラスのprivateメソッドと同名のメソッドをサブクラスで定義しない
-
privateメソッドはサブクラスからはオーバーライドできず、別々のメソッドとして扱われる
- 同じ名前でも複数存在してしまうこととなる。
-
サブクラスが存在する場合、スーパークラスの既存のpublic,またはprotectedメソッドを後からprivateに変更しない
>悪い例
public class GraphParts {
:
private void drawGraphTitle() {
:
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class CustomeGraphParts extends GraphParts {
private void drawGraphTitle() {
:
}
}
privateメソッドはサブクラスからはオーバーライドできないメソッドです。
継承関係にあるクラス同士の同名のprivateメソッドは、別名のメソッド同様に扱われます。
継承関係になる同名のprivateメソッドはエラーにならない!
80.★★equalsメソッドを実装した場合にはhashCodeメソッドも実装する
- HashMap,HashSet,Hashtableなどのハッシュを利用したコレクションを格納する際に正しく動作させるため
>良い例
public class DataBox{
boolean editable = true;
int historyNo = 0;
long longNumber = 0L;
double value = 0.0;
String dataName = null;
int[] dataArray = null;
@Override
public int hashCode(){
int baseNumber = 31;
int result = 17;
// booleanのhash値
result = baseNumber * result + (editable ? 0: 1);
// intのhash値
result = baseNumber * result + hisotyNo;
// longのhash値
result = baseNumber * result + (int)(longNumber ^ (longNumber >>> 32)));
long work = Double.doubleToLongBits(value);
// doubleのhash値
result = baseNumber * result + (int)(work ^ (work >>> 32));
if(dataName == null){
result = baseNumber * result;
}else{
// オブジェクト型のhash値
result = baseNumber * result + dataName.hashCode();
}
if(dataArray == null){
result = baseNumber * result;
}else{
// プリミティブ型の配列のhash値
result = baseNumber * result + Arrays.hashCode(dataArray);
}
return result;
}
}
81.★★Cloneableインタフェースは明示的に実装
- Object.clone()をオーバーライドする。
- どんな場合でも、cloneメソッド内でのsuper.cloneの呼び出しは必須
>良い例
public class DataBox implements Clonable {
int historyNo = 0;
double value = 0;
String dataName = null;
@Override
public DataBox clone() {
try{
return (DataBox)super.clone();
}catch (CloneNotSuportedException e){
throw new AssertionError();
}
}
}
>悪い例
public class DataBox {
int historyNo = 0;
double value = 0;
String dataName = null;
@Override
public DataBox clone(){
try{
return (DataBox)super.clone();
}catch (CloneNotSuportedException e){
throw new AssertionError();
}
}
}
implemets Cloneableがなければエラー(CloneNotSupportedException)がでる
- オブジェクトを複製する方法として、コピーコンストラクタを実装する例がある。
>コピーコンストラクタ実装例
public class DataBox{
int historyNo = 0;
double value = 0.0;
String dataName = null;
public DataBox (DataBox dataBox){
history = dataBox.history;
value = dataBox.value;
dataName = dataBox.dataName;
}
}
2.9 インスタンス
82.★★オブジェクト同士はequalsメソッドで比較する
-
同じクラスの2つのインスタンスが保持している値の同値値を判定するにはequalsメソッドを使う
-
オブジェクト同士は「==」では比較しない
- 「=」はプリミティブ型のみ
-
オブジェクトとnullとの比較にはequalsは使わない
- この場合「==」か「!=」を使用する
-
Stringではequalsで比較をする
-
equaをオーバーライドしている主なクラスは以下の通り
- ArrayList, LinkedList, Vector
- BigDecimal
- Color
- Date
- Double
- File
- Float
- HashMap, TreeMap, EnumMap
- HashSet,TreeSet,EnumSet
- Integer
- Long
- String
83.★instanceofをキャスト可否判断に使う
-
クラス型同士のキャスト変換を行う際は、キャストが可能か明確にするひつようがある
-
キャスト変換できない型に対してキャストするとエラーのもと
-
instanceofを使うことによってキャスト変換可能かどうかわかる。
>良い例
@Override
public boolean equals(Object query){
if(queru instanceOf Developper){
Developer developer = (Developer)query;
if((this.developmentChargeID.equals(developer.developmentChargeID))
&& (this.developmentChargeName.equals(developer.developmentChargeName))
&& (this.developmentChargegrpID.equals(developer.developmentChargegrpID))){
return true;
}
}
return false;
}
>悪い例
@Override
public boolean equals(Object query){
Developer developer = (Developer)query;
if((this.developmentChargeID.equals(developer.developmentChargeID))
&& (this.developmentChargeName.equals(developer.developmentChargeName))
&& (this.developmentChargegrpID.equals(developer.developmentChargegrpID))){
return true;
}
return false;
}
2.10 制御構造
84.★★制御文の「{}」は省略しない
- 制御文周りは「{}」で囲う
- 一行だとなくても動作はするけど可読性をあげるために徹底すること
85.★for分では3つのカウンタ条件を完備させる
-
for文を記述する際には3つの式を入れる
- カウンタ初期化式
- 繰り返し条件式
- カウンタ更新式
-
3つの条件式があわないためループをfor文を扱うべきか再考する
-
イテレーターを使った記述ではばカウンタ更新式を書かない
-
Java SE 5.0からはfor-each文も使える
繰り返し条件式はループの回数文実行されます。この式が処理時間の大きいメソッドを含んでいるとアプリケーションのパフォーマンスが悪化します。
86.★for文とwhile文を正しく使い分ける
- ループ構造の制御では、for、拡張for文(for-each文)、do-while文、do-while文を正しく使い分ける
文 | タイミング | 終了タイミング |
---|---|---|
for文 | 繰り返しの終了判定にループを数えるカウンタ、またらイテレータの使用が当てはまるときに使います。 | 終了タイミングは毎回ループの直前 |
拡張for文 | 配列またはコレクションの全要素に処理を適用する場合に使います | 終了判定のタイミングは毎回のループの直前 |
while | for文に適さないカウンタ、またはカウンタ以外の終了条件でループの終了を判定する場合に使います | 終了判定のタイミングは毎回のループの直前 |
do-while文 | カウンタまたはイテレータ以外でループの終了を判定する場合に使います | 終了判定のタイミングは毎回のループの最後。そのため最低1回はループの中実行する |
- イテレータを用いた多重ループ
String[] brand = {"ASAHI", "KIRIN", "SUNTORY"};
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
Collection<String> brandName = Arrays.asList(brand);
Collection<String> sizeLabel = Arrays.asList(size);
List<ItemLabel> items = new ArrayList<ItemLabel>();
for(Iterator<String> i = brandName.iterator(); i.hasNext(); ){
String brandTemp = i.next();
for(Iterator<String> j = sizeLabel.iterator(); j.hasNext(); ){
items.add(new ItemLabel(brandTemp, j.next()));
}
}
87.★★for文を利用した繰り返し処理の中でカウンタ変数の値を変更しない
- for文の中でカウンタ変数を変更しない
- ループ構造がわかりにくくなる
88.★配列やコレクションを処理するループに拡張for文を使う
-
配列やコレクションに格納されたオブジェクトとの集合に対しての処理
- 拡張for文を使う
-
拡張for文が扱えるコレクションはArrayList、LinkedList、HashSet、TreeSetなど
>良い例1
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
List<ItemLabel> items = new ArrayList<ItemLabel>();
for(String i: brand){
for(String j: size){
items.add(new ItemLabel(i, j));
}
}
>良い例2
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
Collection<String> brandName = Arrays.asList(brand);
Collection<String> sizeLabel = Arrays.asList(size);
List<ItemLabel> items = new ArrayList<ItemLabel>();
for(String i: brandName){
for(String j: sizeLabel){
items.add(new ItemLabel(i, j));
}
}
>拡張for文を使わない例
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
List<ItemLabel> items = new ArrayList<ItemLabel>();
for(int i=0;i<=brand.length;i++){
for(int i=0;i<=size.length;i++){
items.add(new ItemLabel(i, j));
}
}
いずれも正しいプログラムではあるものの、拡張for文のほうが可読性が高い。
拡張for文を使っていきましょう
- 繰り返し処理中のオブジェクトの生成は要否を考える
-
ループ内でオブジェクト生成してすぐに破壊する処理があると消費メモリと処理時間のコストが大きくなる
- ループの内側でのnewを避けてコーディングする。
-
オブジェクトを再利用するようにする
-
ラッパークラス型もループの内側では使用しない。
>良い例
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
StringBuilder stringTemp = new StringBuilder();
for(int i = 0; i < brand.length; i++ ){
stringTemp.delete(0, stringTemp.length());
:
}
>悪い例
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
for(int i = 0; i < brand.length; i++ ){
StringBuilder stringTemp = new StringBuilder();
stringTemp.delete(0, stringTemp.length());
:
}
- ただしループ内でのオブジェクト生成が完全な空くとは言い難い
- 宣言と同時に初期化することによってオブジェクトの無駄な生成と破棄を回避できる
String message = null;
for (int i = 0; i < brand.length; i++ ){
for(int j = 0; j < size.length; j++){
message = buildMessage(brand[i], size[j]);
:
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int i = 0; i < brand.length; i++ ){
for(int j = 0; j < size.length; j++){
String message = buildMessage(brand[i], size[j]);
:
}
}
90.★繰り返し処理のループの中に tyr/catch ブロックを記述しない
- try/catchブロックは、繰り返しループ内側に記述すると、アプリケーションのパフォーマンスを悪化させてしまう
- 特別な理由がない限りループの外側
>良い例
try{
for (int i = 0; i < brand.length; i++){
for (int j = 0; j < size.length; j++){
displayLabel(brand[i], size[j]);
}
}
} catch (ProjectDashboardException e){
:
}
>悪い例
for (int i = 0; i < brand.length; i++){
for (int j = 0; j < size.length; j++){
try{
displayLabel(brand[i], size[j]);
} catch (ProjectDashboardException e){
//...
}
}
}
91.★switch文ではcaseごとにbreakを書く
-
次のcaseを続けて実行したい場合は、最初のcaseブロック内の最後にコメント記述する
-
defaultにもbreakまたはreturnをかく
>良い例
switch (style.getChartStyle()) {
case LineAndBar:
dataSet.setValue(getPage(), "ページ数", processName);
break;
case DotLine:
// DotLineとLineは同じ設定を行う
case Line:
dataSet.setValue(Integer.pagit rseInt(style.get("size")), "ドキュメント数",
processName);
break;
:
default:
assert false;
break;
}
プログラムの可読性を損なわないために、switch文では、caseごとにbreakすることを標準的なスタイルとする。
92.★★switch文ではdefaultを必ず書きbreakも書く
- caseを記述した後、最後に必ずdeaultを記述する
- defaultの末尾にはbreakまたはreturnを記述する
絶対にcaseの後ろにdefaultをかくこと!
- switch文で文字列による分岐の際に文字列をnullチェックする(JavaSE7以降)
- switchの式にString型が使用できる
- nullの場合エラーが出るため式の値をチェックするように
>良い例
String charStyle = style.getCharStyleString();
if(charStyle == null ) {
return;
}
switch (style.getChartStyle()) {
case "LineAndBar":
dataSet.setValue(getPage(), "ページ数", processName);
break;
case "Line":
dataSet.setValue(Integer.parseInt(style.get("size")), "ドキュメント数",
processName);
break;
:
default:
break;
}
2.11 コレクション
- CollectionやMapにはジェネリクスを使う
ジェネリクスとは、プログラミング言語の機能・仕様の一つで、同じプログラムコードで様々なデータ型のデータを処理できるようにするもの。
- ジェネリクスを入れなければ全てObject型になってしまうためバグのもと
>良い例1
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
List<ItemLabel> items = new ArrayList<ItemLabel>();
List<ItemLabel> items = new ArrayList<>();
>良い例2
// 宣言と初期化が離れている場合
List<ItemLabel> items;
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
items = new ArrayList<ItemLabel>();
95.★オブジェクトの集合の繰り返し処理にはStream APIを使用する(JavaSE8以降)
-
コレクションに格納されたオブジェクト集合に対して、各要素に同じ処理を適用したいときにはStream APIを使用する
-
stereamメソッドが使用できる主なコレクションは
- ArrayList
- LinkedList
- HashSet
- TreeSet
- など...
>良い例
String[] brand = {"ASAHI", "KIRIN", "SUNTRY"}
String[] size = {"2Liter", "1Liter", "500ml", "300ml"};
:
List<ItemLabel> items = new ArrayList<ItemLabel>();
Arrays.stream(brand)
.forEach(br -> Arrays.Stream(size)
.forEach(sz -> items.add(new ItemLabel(br, sz))));
Stream<ItemLabel> itemStream = items.stream();
itemsStream.forEach(e -> System.out.println(e));
CPUのマルチコア化によって、小さい粒度の処理でも並列動作させることに意義が生じています。
ストリームはコレクションを用いた繰り返し処理の並列動作を簡単に実現する手段としてその利用価値は高い。
2.12 ストリーム操作
96.AutoCloseableを実装していないストリームを扱うときはfinallyブロックでクローズ処理をする
97.AutoCloseableを実装しているストリームを扱うときはリソース付きtry文を使用する(JavaSE7以降)
98.ObjectOutStreamではresetメソッドを使用する
99.ストリームの操作でバッファ入出力を使う
2.13 例外処理
100.catch文でキャッチする例外は詳細な例外クラスでキャッチする
101.★★Exceptionクラスのオブジェクトを生成してスローしない
102.finallyブロックには戻り値に影響がある記述をしない
103.★★catchブロックでは必ず処理をする
- 処理を記述できない場合はログ出力、メッセージ出力またはスタックトレース出力を例外処理として記述する
104.Error,Throwableクラスを継承しない
2.14 ガベージコレクション
105.finalizeはオーバーライドしない
106.アプリケーションからfinalizeを呼び出さない
3 コメントおよびアノテーションに関する規約
3.1 全般
107.★コメントは説明したいコードの直前の行に記述する
108.★★★コメントは必要なものだけを簡潔に書く
109.コメントアウトしたプログラムの断片を次工程まで放置しない
3.2 Javadoc
110.★★Javadocの記述を揃える
- クラスドキュメントでは最初にクラスの役割や機能を簡潔に書く。
- 使用の詳細を記す場合は
<p>
タグで段落を分ける
- 使用の詳細を記す場合は
3.3 アノテーション
111.オーバーライドするメソッドにはOverrideアノテーションを使用する
112.関数型インタフェースの定義にはFunctionalInterfaceアノテーションを使用する(JavaSE8 以降)
用語集
-
アクセッサ
- ゲッター、セッターのこと
-
ガベージコレクション
- コンピュータプログラムが動的に確保したメモリ領域のうち、不要になった領域を自動的に解放する機能
-
コンバーターメソッド
- オブジェクトを変換するメソッドの総称
- 「toString()」メソッドなど
- オブジェクトを変換するメソッドの総称
-
ジェネリクス
- Listの宣言時に<〜>で囲むことで型を指定できる機能
-
循環的複雑度(サイクロマティック複雑度)
- ソフトウェア測定法の一つでソースコードがどれぐらい複雑であるかをメソッド単位で数値にして表す指標
-
ストリームAPI
- コレクションや配列などのデータをもとにデータの加工や、集計を行うAPIです。ストリームはデータの処理した結果を次の処理へ渡すことができるので、複数の処理をメソッドチェーンで繋ぐことができます。 ->ストリームパイプライン
-
コンストラクタ⇔デストラクタ
- (コンストラクタ)クラスのインスタンスが作られた直後に自動的に実行されるメンバ関数です。
- (デストラクタ)クラスのインスタンスが消える直前に自動的に実行されるメンバ関数です。
-
ファクトリーメソッド
- インスタンスの作り方をスーパークラスで定め、具体的な処理をサブクラスで行うパターンをファクトリーメソッド(Factory Method)パターンと呼ぶ
-
プレフィックス
- 接続辞
-
コンテキスト(コンテクスト)
- 文脈?(結構抽象的)
-
シャローコピー、ディープコピー
-
ラムダ式
- JavaSE 8から導入された構文で、大雑把にいうならば、メソッドをシンプルに表すための構文
-
リテラル
- コンピュータプログラムのソースコードなどの中に、特定のデータ型の値を直に記載したもの
覚えたいリスト
★★★絶対に覚えておきたい
命名規約
規約NO | 概要 | カテゴリー |
---|---|---|
規約1 | 名前には英単語を使用する | 全般 |
規約6 | クラス名は役割を表す名前にする | クラス |
規約7 | クラス名はPascal形式で記述する | クラス |
規約8 | クラス名はフルスペルで記述する | クラス |
規約13 | メソッド名は目的のわかる名前にする | メソッド |
規約14 | メソッド名はCamel形式で記述する | メソッド |
規約15 | メソッドの役割の対称性を意識する | メソッド |
規約19 | 変数には意味のある名前を付ける | 変数 |
規約20 | 変数名はCamel形式で記述する | 変数 |
決めごと
規約NO | 概要 | カテゴリー |
---|---|---|
規約6 | クラス名は役割を表す名前にする | クラス |
規約13 | メソッド名は目的のわかる名前にする | メソッド |
規約19 | 変数には意味のある名前を付ける | 変数 |
規約108 | コメントは必要なものだけを簡潔に書く | 書き方 |
★★できることなら覚えたい
規約NO | 概要 | カテゴリー |
---|---|---|
規約3 | パッケージ名はすべて小文字にする | 書き方 |
規約5 | インポートでは*を省略しない | 書き方 |
規約9 | 抽象クラスの名前には「Abstract」を付ける | クラス |
規約10 | インタフェース名はクラス名に準ずる | クラス |
規約23 | 引数名とフィールド名が同じなることを回避する | 書き方 |
規約24 | 定数名は「_」で区切った大文字表記とする | 変数 |
規約25 | 1つのクラスは1つのソースファイルで定義する | クラス |
規約32 | クラス定義の記述順序を守る | クラス |
規約33 | 110行を超える行は改行または文を分割する | 書き方 |
規約34 | 行の途中での改行は、カンマの後、演算子の前、節(予約語)の前とする | 書き方 |
規約35 | クラスとメソッドの宣言行およびブロック開始行の末尾に「{」を記述する | 書き方 |
規約36 | 「{」の後ろにステートメントを記述しない | 書き方 |
規約37 | インデントは半角の空白文字を使い4桁分とする | 書き方 |
規約38 | ブラックの開始行と終了行のインデントを揃える | 書き方 |
規約39 | ブロック内部のインデントを揃える | 書き方 |
規約41 | 1行に2つ以上のステートメントを書かない | 書き方 |
規約44 | カンマ、セミコロン、コロンの後ろや演算子の前後に空白を入れる | 書き方 |
規約47 | メソッドのないインターフェースを定義せず定数クラスを使う | メソッド |
規約49 | メソッドの最大行数は150行とする | メソッド |
規約50 | 循環的複雑度の上限を19とする | 書き方 |
規約54 | 引数の数は少なめにする | 書き方 |
規約59 | 配列の宣言は型名に「[]」を付けて行う | 書き方 |
規約68 | ローカル変数名とフィールド名が同じになることを回避する | 書き方 |
規約80 | equalsメソッドを実装した場合にはhashCodeメソッドも実装する | メソッド |
規約81 | Cloneableインタフェースは明示的に実装する | メソッド |
規約82 | オブジェクト同士はequalsメソッドで比較する | メソッド |
規約84 | 制御文の「{}」省略しない | 書き方 |
規約87 | for文を利用した繰り返し処理の中でカウンタ変数を変更しない | 書き方 |
規約92 | switch文ではdefaultを必ず書きbreakも書く | 書き方 |
規約101 | Exceptionクラスのオブジェクトを生成してスローしない | クラス |
規約103 | catchブロックでは必ず処理をする | 書き方 |
規約110 | Javadocの記述を揃える | 書き方 |
★覚えておくべき
規約NO | 概要 | カテゴリー |
---|---|---|
規約2 | 大文字と小文字で名前を区別しない | 変数 |
規約11 | 例外クラス名の末尾に「Exception」を付ける | クラス |
規約16 | ゲッターメソッド名は「get+属性名」とする | クラス |
規約17 | セッターメソッド名は「set+属性名」とする | クラス |
規約18 | booleanを返すメソッドはtrue/falseの識別がわかる名前にする | メソッド |
規約21 | boolean型の変数はtrue/falseの識別がわかる名前にする | 変数 |
規約28 | クラスやメソッドのアクセス修飾子の宣言は適切な権限で行う | 書き方 |
規約30 | プリミティブ型と参照型の違いを認識する | 書き方 |
規約31 | ラッパークラスよりプリミティブ型のを使う | 書き方 |
規約40 | 無駄な空行は入れず意味のある切れ目で入れる | 書き方 |
規約42 | 比較演算子は「<」か「<=」を使う | 書き方 |
規約48 | 定数クラスにはstaticイニシャライザを使う | 書き方 |
規約52 | メソッドの引数の順序には根拠がある | 書き方 |
規約53 | 配列やコレクションを返すメソッドではnullを返さない | 書き方 |
規約55 | 引数の正当性を検査する | 書き方 |
規約57 | 定数はstatic fainalを宣言する | 書き方 |
規約58 | リテラルは原則として使わず定数を使う | 書き方 |
規約60 | 配列は宣言時に大きさを明確にする | 変数 |
規約61 | 2次元以上の配列を宣言しない | 変数 |
規約64 | インスタンス変数はprivateで宣言する | 変数 |
規約67 | クラス変数はクラス名を使ってアクセスする | 変数 |
規約70 | ローカル変数は使用する直前に初めて宣言と初期化を行う | 変数 |
規約71 | 更新される文字列にはStringBuilderを使用する | 変数 |
規約72 | 更新されない文字列にはStringを使用する | 変数 |
規約75 | 数値の制度に気を付ける | 変数 |
規約83 | instanceofをキャスト可否判断に使う | 変数 |
規約85 | for分では3つのカウンタ条件を完備させる | 書き方 |
規約86 | for文とwhile文を正しく使い分ける | 書き方 |
規約88 | 配列やコレクションを処理するループに拡張for文を使う | 書き方 |
規約90 | 繰り返し処理のループの中に tyr/catch ブロックを記述しない | 書き方 |
規約91 | switch文ではcaseごとにbreakを書く | 書き方 |
規約95 | オブジェクトの集合の繰り返し処理にはStream APIを使用する(JavaSE8以降) | 書き方 |
規約107 | コメントは説明したいコードの直前の行に記述する | 書き方 |
補足
★★★と★★はEclipseのCheckstyleである程度チェック可能
-
最初にプロジェクトを立ち上げたら規約を設定し、ルールを明確化する
-
行程中ではつねに静的解析を行う
- Checkstyleの活用