4. メソッド、コンストラクタを実装するときは
publicなメソッドに対してはJavadocの@throwsタグを
使って文章化
/**
* 値が(this mod m)であるBigIntegerを返します。このメソッドは、
* remainderメソッドとは異なり、常に負でないBigIntegerを返します。
*
* @param m 正でなければならない
* @return this mod m
* @throws ArithmeticException m <= 0の場合 <=チェック内容を文章化
*/
public BigInteger mod(BigInteger m) {
if (m.signum() <= 0) {
throw new ArithmeticException();
}
...//計算を行う
}
10. //一見問題ないコード
public class Period {
private final Date start;
private final Date end;
/**
* @param start 期間の開始
* @param end 期間の終わりで、開始より前であってはならない。
* @throws IllegalArgumentException start が end の後の場合。
* @throws NullPointerException start か end がnullの場合。
*
*/
public Period(Date start, Date end) {
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException(start + " after " + end);
}
this.start = start;
this.end = end;
}
public Date getStart() {
return start;
}
public Date getEnd() {
return end;
}
//残りは省略
}
11. // Periodインスタンスの内部を攻撃
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear( 77); // pの内部を変更する!!
一見すると、期間の開始と終わりの後には絶対
こないように見えるけどDateは可変なので、
簡単に終わり(end)を変えられる。
12. 対策
コンストラクタで可変なパラメータのコピーし
ちゃう。
(ここでは新しいDateオブジェクトを作成)
// 修正されたコンストラクタ - パラメータの防御的コピーをする
public Period(Date start, Date end) {
this start = new Date(start.getTime);
this end = new Date(end.getTime);
if (this.start.compareTo(this.end) > 0) {
throw new IllegalArgumentException(start + " after " + end);
}
}
さっきみたいに
end.setYear(78);
ってやっても
参照しているオブジェクトが
違うから変更されない。
15. // Periodインスタンスの内部への第2の攻撃
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.getEnd.setYear(78); // pの内部を変更する!!
実はまだ、Periodクラスは攻撃から上手く防御
できてない。
setterで変更できちゃう
17. public class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException();
}
this.start = start;
this.end = end;
}
public Date getStart() {
return start;
}
public Date getEnd() {
return end;
}
//残りは省略
}
public class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException();
}
this start = new Date(start.getTime);
this end = new Date(end.getTime);
}
public Date getStart() {
return new Date(start.getTime);
}
public Date getEnd() {
return new Date(end.getTime);
}
//残りは省略
}
※ただ一番いいのはDateではなく、Date.getTimeで取得される基
本型のlong値を使う方法。
変更前 変更後
28. 項目38 可変長引数を注意して使用する
static int sum(int args... ) {
int sum = 0;
for (int arg : args) {
sum += arg;
}
return sum;
}
可変長引数メソッドの例
(0個の場合もOK)
29. static int sum(int args... ) {
if (args.length == 0) {
throw new IllegalArgumentException("Too few arguments");
}
int min = args[0];
for (int i = 1; i < args.length; i++) {
if (args[i] < min) {
min = args[i];
}
}
return min;
}
可変長引数メソッドの例
(0個の場合はNG、 必ず1つ以上)
問題点
・引数なしてこのメソッドを呼んだ場合、コンパイル時でなく、実行時に失敗する。
・メソッドが見づらい
・argsに対して明示的なチェックをしないと行けない
・minをInteger.MAX_VALUEへ初期化しないと、for-eachが使えない
30. static int sum(int firstArg, int remainingArgs... ) {
int min = firstArg;
for (int arg : remainingArgs) {
if (arg < min) {
min = arg;
}
}
return min;
}
解決策
・引数が0の場合はfor分に入らないのでOK
・前より見やすい
38. メソッドとクラスとで、書き方を変える
1.クラス、インターフェイスの場合
クラス、インターフェイスのによって表される自柄を説明している
名詞句であるべき
例) TimerTask -- A task that can be scheduled for one-time or repeated execution by aTimer
Math.PI -- The double value that is closer than any other to pi,the ratio of the
circumference of a circle to its diameter
2.メソッド、コンストラクタの場合
メソッドやコンストラクタが行う処理を説明している動詞句であるべき
例) ArrayList(int initialCapacity)-- Constructs an empty list with the specified initial capacity
Collection.size()-- Returns the number of elements in this collection