Цикломатична складність при виклику одного і того ж методу кілька разів


12

Завдяки питанню в Code Review я зіткнувся з невеликою суперечкою (що по суті є можливістю дізнатися щось) про те, що саме є цикломатичною складністю для наведеного нижче коду.

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 Cyclomatic Complexity для основного методу дорівнює 2, а для throметоду - 2.

Однак хтось інший каже мені, що складність виклику throкілька разів є number of calls * method complexity, і тому стверджує, що складність основного методу становить 7 * 2 = 14.

Ми вимірюємо різні речі? Чи можемо ми обидва бути правильними? Або яка реальна цикломатична складність тут?


5
ЦК функції два, так як є лише два шляхи наскрізь. КК програми вище. Це повний забій у темряві, але я припускаю, що програмне забезпечення для аналізу коду приймає кожну функцію як окрему чорну скриньку через неможливість обчислити CC всього складного додатку за один раз.
Фоші

@Phoshi Якщо ви напишете це як відповідь і (якщо можливо) наведіть посилання, що свідчить про те, що є розділення обох, я б із задоволенням прийняв цю відповідь.
Саймон Форсберг

Якщо порахувати всі шляхи, спричинені можливими винятками в вимірюваннях CC, Бог допоможе хлопцеві, який задав питання про рефакторинг якогось тривіального коду, щоб отримати число під 10.
mattnz

Відповіді:


9

Коли я це правильно зрозумів, цикломатическая складність з main8 - тобто число лінійно незалежних шляхів через код. Ви отримуєте виняток в одному з семи рядків, або жоден, але ніколи більше одного. Кожна з можливих «точок виключення» відповідає точно одному різному шляху через код.

Я думаю, коли МакКейб винайшов цю метрику, у нього не було мов програмування, за винятком обробки.


Але чи дійсно має значення, який з рядків викидає виняток?
Саймон Форсберг

5
@ SimonAndréForsberg: так, це так. Подумайте, що "thro" має побічний ефект, коли він збільшує глобальний лічильник, коли він викликається (це не змінило б можливі шляхи через код). Тоді можливі результати цього лічильника - від 0 до 7, тому це доводить, що КК становить щонайменше 8.
Док Браун

Ви б сказали, що плагін, який я використовую, повідомляє про невірне значення для mainметоду?
Саймон Форсберг

@ SimonAndréForsberg: ну, я не знаю ваш плагін для метрики, але 2, очевидно, немає 8.
Doc Brown

У моєму питанні є посилання на плагін метрик ....
Саймон Форсберг

6

Будучи "іншим хлопцем", я відповім тут і буду точним щодо того, що я говорю (що я не був особливо точним з іншими формами).

Використовуючи наведений вище приклад коду, я обчислюю цикломатичну складність як 8, і у мене є коментарі в коді, щоб показати, як я обчислюю це. Для опису шляху я буду вважати успішну прохідний все ті thro()виклики , як «основним» «кодом шлях» (або «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пункт не сприяє складності методу, catchце просто ціль throwsгілки, і, таким чином, блок лову, який є цільовим throwчислом s, рахується 1 раз для кожного throw, і не один раз за все.


Чи підраховуєте ви також можливі гілки для OutOfMemoryExceptions? Я маю на увазі педантично, вони можуть викликати гілки коду, але ніхто їх не рахує, оскільки вони розбавляють корисність показника.
Теластин

Ні, я не ... і ти маєш рацію, але, в контексті цього аргументу, я рахую лише ті винятки, які метод оголошується кинутим. Крім того, якщо метод оголошує три винятки, але код callinch робить це, catch (Throwable t) {...то я гадаю, це не має значення, скільки винятків він оголошує кинутим.
rolfl
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.