おかげで コードレビューでの質問 以下のコードの正確な循環的複雑度について、少し意見が分かれました(これは本質的に何かを学ぶ機会です)。
public static void main(String[] args) {
try {
thro();
thro();
thro();
thro();
thro();
thro();
thro();
}
catch (NullPointerException e) {
}
}
private static Random random = new Random();
public static void thro() throws NullPointerException {
if (random.nextBoolean())
throw new NullPointerException();
System.out.println("No crash this time");
}
このコードをEclipseで記述して Eclipseメトリックプラグイン を使用すると、メインメソッドのMcCabe循環的複雑度は2であり、thro
メソッドの場合は2と表示されます。
ただし、thro
を複数回呼び出すことの複雑さはnumber of calls * method complexity
、したがって、メインメソッドの複雑さは7 * 2 = 14であると主張しています。
異なるものを測定していますか?どちらも正しいのでしょうか?または、ここで実際の循環的複雑度は何ですか?
これを正しく理解すると、main
の- Cyclomatic Complexity は8になります。これは、コードを通る線形独立パスの数です。 7行のいずれかで例外が発生するか、1つでも例外は発生しませんが、1行を超えることはありません。その可能な「例外ポイント」のそれぞれは、コードを通る1つの異なるパスに正確に対応しています。
McCabeがその測定基準を発明したとき、彼は例外処理を考慮したプログラミング言語を持っていなかったと思います。
「もう一人の男」なので、ここで答え、私が言うことを正確に説明します(他の形式では特に正確ではありませんでした)。
上記のコード例を使用して、循環的複雑度を8として計算します。コードにコメントを付けて、計算方法を示します。パスを説明するために、allthro()
呼び出しによるループが「メイン」「コードパス」(または「CP = 1」)として成功したループを考えます。
public static void main(String[] args) {
try {
// This is the 'main' Code Path: CP = 1
thro(); // this has a branch, can succeed CP=1 or throw CP=2
thro(); // this has a branch, can succeed CP=1 or throw CP=3
thro(); // this has a branch, can succeed CP=1 or throw CP=4
thro(); // this has a branch, can succeed CP=1 or throw CP=5
thro(); // this has a branch, can succeed CP=1 or throw CP=6
thro(); // this has a branch, can succeed CP=1 or throw CP=7
thro(); // this has a branch, can succeed CP=1 or throw CP=8
}
catch (NullPointerException e) {
}
}
したがって、私はこのメインメソッドで8つのコードパスをカウントします。これは、8の循環的複雑度です。
Java用語では、関数を終了するための各メカニズムはその複雑さに数えられます。そのため、成功状態を持ち、たとえば最大3つの例外をスローするメソッドは4文書化された出口パス。
このような関数を呼び出すメソッドの複雑さは次のとおりです。
CC(method) = 1 + sum (methodCallComplexity - 1)
私が考えている他のことは、私の意見では、catch
句はnotがメソッドの複雑さの一因となるということです。catch
は単にターゲットですthrows
ブランチの1つであり、したがって、複数のthrow
sのターゲットであるキャッチブロックは、各throw
に対して1回だけカウントされます。