導入
前回に続いてコーディングのルールを学習しましょう。今回はコードフォーマットのルールです。コードフォーマットとは、
展開
コードフォーマットのルールについて、
基本的には自由
Java言語のソースコードはとても自由に書くことができます。一行にずらずらっと続けて書いても良いし、freewheeling.
のように自由奔放な書き方でもきちんと動きます。
int c = 1;boolean P;
for(int i = 0; i<10; i++)for(int j = 0; j<10; j++){
P = true;if(c == 1)P = false;
else for(int n=2; n<c; n++)
if (c % n == 0){P = false;
break;}if (P)fill(255,0,0);
else fill(255,255,255);rect(j*10,i*10,10,10);c++;}
さてしかし、
プログラミングの世界には
freewheeling.
が何をするsketchか読み取ってみましょう。5分間で結構です。それ以上の時間をかけるのは時間の無駄ですから。
式は自然な形で書きましょう
コードの書き方は様々です。目的に応じて書き分けます。最もポピュラーなのが
最も単純な例として次のコードSpeedOrClear.
を紹介しましょう。
//スピード重視
int x = 2;
x = x << 1;
println("x * 2 = " + x);
//分かりやすさ重視
int y = 2;
y = y * 2;
println("y * 2 = " + y);
スピード重視の計算式では変数x
に格納した整数値を1ビット左へシフトしています。これは2進数の数値を左へ1ビットシフトすることが、y
の値を2倍しています。
ほんのわずかでも実行速度を高めたいならば、
しかしながら、*
を用いた方が誤解が無いでしょう。
millis()
メソッドで取得できます。
不等式では右ほど大きく
数値の大小を条件判断文で判定する場合、GoodIsLess.
)。どちらが大きくなるか全く予想がつかない場合にも、<
を使って式をたてましょう。文化的に、
int a = 1;
int b = 2;
// Good example
if (a < b) {
println("That's natural!");
} else {
println("That's funny!");
}
// Bad example
if (a > b) {
println("That's natural!");
} else {
println("That's funny!");
}
カッコを使って式の曖昧さを解消しましょう
早速ですが次の例題2問を検討してください。
例題1
整数変数a
, b
に代入された数値の平均を取りたいとします。次の式が正しい結果を得られるように変更してください。
x = a + b / 2
このまま計算すると、a
」b
の半分」
x = (a + b) / 2
果たして正しい平均値が得られるはずです。
例題2
次の式を正しく計算するコードを書いてください

先ほどの例題とよく似た形です。今度は分母にも注意が必要です。次のようにコードを書くと正しく計算されません。
x = 9.53 + 5.32 / log(1.81) * sqrt(7.52)
理由は2つあります。
- 分子の加算をカッコで囲む必要があります。加算より除算が優先されるからです。
- 分母全体をカッコで囲むか、
平方根の項の直前の乗算を除算に変更する必要があります。カッコが無ければ、 対数の直前の除算演算子で表現したかった分数が平方根の直前で終了してしまうからです。
正しく計算するためには次のように書きます。
x = (9.53 + 5.32) / (log(1.81) * sqrt(7.52)) ...(A)
あるいは次のように書きます。
x = (9.53 + 5.32) / log(1.81) / sqrt(7.52) ...(B)
式(A)の方が例題の式の形をイメージしやすいので、
273 + t
v = 287.03 ---------
p
v = 体積[m^3]
p = 圧力[Pa]
t = 温度[℃]
複雑な式は分割しましょう
さて、

この式に仮の値を代入して計算するsketchは次のようになりますDivide_
)。
float x = 0;
float c = 1;
float m = 2;
float t = 3;
float x0 = 4;
float k = 5;
float v0 = 6;
//----------(1)
x = exp(-c/(2*m)*t)
* (
x0 * cos((sqrt(4*m*k - pow(c,2)))/(2*m)*t )
+ (2*m*v0 + c * x0)/(sqrt(4*m*k - pow(c,2)))
* sin( (sqrt(4*m*k - pow(c,2))/(2*m) * t ) )
);
println("x = "+x);
float val1 = sqrt(4*m*k-pow(c,2));
float val2 = val1 / (2*m);
float x2 = 0;
//----------(2)
x2 = exp(-c/(2*m)*t)
* (x0 * cos(val2 * t) + (2*m*v0 + c*x0)/val1 * sin(val2 * t) );
println("x2 = "+x2);
(1)も(2)も同じ計算をしています。どちらが式を読み取りやすいでしょうか。
(1)の式が正しく記述されているかを確認するには骨が折れそうですね。(2)はプログラミングの金言
分割統治とは、
(1)の式をよく見ると式の中には共通した形が数カ所あります。それらを(2)の式のようにまとめてみましょう。(2)の式は随分見通しが良くなりました。val1
とval2
の定義も直前にありますから迷うことは無いでしょう。
このように、
適切に改行し、適切にインデントをしよう
今回冒頭で紹介した悪夢のようなコードを再度取り上げます。
int c = 1;boolean P;
for(int i = 0; i<10; i++)for(int j = 0; j<10; j++){
P = true;if(c == 1)P = false;
else for(int n=2; n<c; n++)
if (c % n == 0){P = false;
break;}if (P)fill(255,0,0);
else fill(255,255,255);rect(j*10,i*10,10,10);c++;}
このコードはまず改行が不適切です。はるか昔……、
freewheeling.
に適切と思われる改行を与えたものが次のsketchNewLines.
です。
int c = 1;
boolean P;
for(int i = 0; i<10; i++)
for(int j = 0; j<10; j++){
P = true;
if(c == 1)P = false;
else
for(int n=2; n<c; n++)
if (c % n == 0){P = false;break;}
if (P)fill(255,0,0);
else fill(255,255,255);
rect(j*10,i*10,10,10);
c++;
}
まだ明瞭とは言えませんが、
当たり前のようですが、
そのように手を入れたのが次のsketch GoodIndents.
です。
int c = 1;
boolean P;
for(int i = 0; i<10; i++)
for(int j = 0; j<10; j++){
P = true;
if(c == 1)
P = false;
else
for(int n=2; n<c; n++)
if (c % n == 0){
P = false;
break;
}
if (P)
fill(255,0,0);
else
fill(255,255,255);
rect(j*10,i*10,10,10);
c++;
}
このコードを実行された方は、
インデントを加えることでかなり読みやすくなっていますが、
- [ことば]
インデントとネスティング - インデント
(indent) は単に行頭を下げることを意味します。ネスティング (nesting) はある構造の中に別の構造を含むことを意味します。Java言語でインデントは通常ネスティングしている場合です。区別できるようにしてください。
ifやforのコードブロックは必ずブレースで囲むこと
if
文やfor
文の抱えるコードブロックは必ずブレース{}
で囲みましょう。どこからどこまでがそのif
やfor
の抱えるコードブロックなのかを明確にするためです。また、if
文やfor
文のインデント位置にそろえましょう。
次のような書き方はやがて自分の首を絞めますBadBlock1.
, BadBlock2.
)。
int a = 0;
int b = 1;
//First version
if (a==b)
println("a = b");
//Second version
if (a==b)
println("a = b");
println("a is equals b");
int a = 0;
int b = 1;
//First version
if (a==b) {
println("a = b");}
//Second version
if (a==b) {
println("a = b");
println("a is equals b");}
BadBlock1.
では最初、a=b
が成り立ったら、Second version
のように書き足したのです。その結果、
最初から次のGoodBlock.
のように書いていれば、BadBlock2.
ではそのようなミスが起きにくいでしょうが、
int a = 0;
int b = 1;
//First version
if (a==b) {
println("a = b");
}
//Second version
if (a==b) {
println("a = b");
println("a is equals b");
}
for
文も、{}
で囲みましょう。ブロック内のコードがたった1行だけでもです。
NewLines.
のfor
文やif
文のコードブロックに不足しているブレースを書き加えましょう。そうするとインデントを容易に入れられるようになります。コードの動きを変えないように注意深く書き加えてください。最後は連載第1回演習3の解答のコードと比較して確認しましょう。
自然に書きましょう
例えばループの使い方ひとつをとっても、GoodAndBadLoopExamples.
の//
のように
int i = 0;
int n = 10;
float[] array;
array = new float[n];
// Bad example 1
while(i<=n-1) array[i++]=1.0;
// Bad example 2
for(i=n;--i>=0; )array[i]=2.0;
// Good example 3
for(i=0;i<n;++i) array[i]=3.0;
// Good example 4
for(i=0;i<array.length;++i) array[i]=4.0;
// Good example 5
i=0;
while(i<array.length){
array[i]=5.0;
++i;
}
// Good example 6
for(i=0;i<array.length;++i){
array[i]=6.0;
}
// Check code 1
for(i=0;i<array.length;++i) {
println("array["+i+"] "+array[i]);
}
// Check code 2
i=0;
for(float val : array){
println("array["+i+"] "+val);
++i;
}
次のことがややこしいと思うはずです。
- Bad example 1
i<=n-1
は単にi<n
の方が良いでしょう。array[i++]=1.
は0 i++
を上手に使っているのですが、 次のように2段階に分けた方がより明瞭です。array[i]=1.
0 ; ++i;- Bad example 2
for(i=n;--i>=0; )
は素直にfor(i=0;i<=n;++i)
と書いた方が分かりやすくなります。カウントが減る方向で処理する理由がないならなおさらです。せめてfor(i=n-1; 0<=i; --i)
のように書きましょう。
for
やwhile
といった制御構造には、
ひとつずつカウントする用途に、while
文を使うのがそもそも不自然ですが、//
のように書くべきです。ついでに補足するならば、//
のように、for
文のコードブロックは、
なるべく一画面に納めよう
なるべく一画面に納めようとするルールは利用するハードウエアの画面サイズに依存するため、
メソッド20行の基準はおそらく、
ひとつのクラスの大きさ、
演習
演習1(難易度:easy)
作業で取り上げた次の式は、
v = 287.03 × (273 + t) / p
v = 体積[m^3]
p = 圧力[Pa]
t = 温度[℃]
温度tに応じて体積がどう変化するかを表すグラフをディスプレイウインドウに表示してください。温度の範囲は0℃から100℃とします。圧力を0.CalcVolume.
としてください。

演習2(難易度:middle)
素数のマスを赤く塗りつぶすsketchを、for
文を使わずwhile
文で書き直してください。ブレースの使い方や改行、PrimeWithWhile.
としてください。
演習3(難易度:easy)
次のデータの集合について、Statistics.
としてください。for
文だけを使う場合、while
文だけを使う場合、
x = {20,19,11,42,36,30,25,44,29,33}
まとめ
- コードフォーマットのルールを学習しました。
- コードは自然に、
読みやすくシンプルに記述しましょう。 - メソッドもクラスも極力短く書きましょう。
学習の確認
それぞれの項目で、
- コードフォーマットの大切さが理解できましたか?
- 理解できた。自分のコードに活かす決心をした。
- 理解できた。しかし、
自分のコードに活かす必要を感じない。 - 理解できない。
- 読みやすいコードの書き方を理解できましたか?
- 理解できた。
- 理解はできるが必要を感じない。
- 理解できない。
参考文献
- 『Javaルールブック ~読みやすく効率的なコードの原則』
(電通国際情報サービス 監修、 大谷晋平、 米林正明、 片山暁雄、 横田健彦 著、 技術評論社) - Javaのコードを書く人は必携。ほぼ見開きでコンパクトながら意を尽くした解説がある。
演習解答
CalcVolume.
pde PrimeWithWhile.
pde for
文のありがたみを痛感しますね。Statistics.
pde