Độ phức tạp theo chu kỳ khi gọi cùng một phương thức nhiều lần


12

Nhờ có một câu hỏi tại Đánh giá mã, tôi đã có một chút bất đồng (về cơ bản là cơ hội để tìm hiểu điều gì đó) về chính xác Độ phức tạp Cyclomatic dành cho mã dưới đây.

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");
}

Khi viết mã này trong Eclipse và sử dụng plugin số liệu Eclipse , nó cho tôi biết rằng Độ phức tạp theo chu kỳ McCabe cho phương thức chính là 2 và đối với throphương thức thì nó nói là 2.

Tuy nhiên, một người khác nói với tôi rằng sự phức tạp của việc gọi thronhiều lần là number of calls * method complexity, và do đó tuyên bố rằng độ phức tạp của phương thức chính là 7 * 2 = 14.

Có phải chúng ta đang đo những thứ khác nhau? Cả hai chúng ta có thể đúng không? Hoặc sự phức tạp chu kỳ thực tế ở đây là gì?


5
CC của hàm là hai, vì chỉ có hai đường dẫn đi qua. CC của chương trình cao hơn. Đây là một cú đâm hoàn toàn trong bóng tối, nhưng tôi cho rằng phần mềm phân tích mã lấy mỗi chức năng như một hộp đen riêng biệt do tính không khả thi của việc tính CC của toàn bộ ứng dụng phức tạp trong một lần.
Phoshi

@Phoshi Nếu bạn viết nó như một câu trả lời và (nếu có thể) cung cấp các liên kết cho thấy có sự tách biệt của hai, tôi sẵn sàng chấp nhận câu trả lời đó.
Simon Forsberg

Nếu bạn đếm tất cả các đường dẫn gây ra bởi các ngoại lệ có thể có trong các phép đo CC, thần sẽ giúp anh chàng hỏi câu hỏi về tái cấu trúc một số mã tầm thường để lấy số dưới 10.
mattnz

Câu trả lời:


9

Khi tôi hiểu điều này một cách chính xác, Độ phức tạp theo chu kỳ mainlà 8 - đó là số lượng đường dẫn độc lập tuyến tính thông qua mã. Bạn có thể có một ngoại lệ tại một trong bảy dòng, hoặc không, nhưng không bao giờ nhiều hơn một dòng. Mỗi "điểm ngoại lệ" có thể tương ứng chính xác với một đường dẫn khác nhau thông qua mã.

Tôi đoán khi McCabe phát minh ra số liệu đó, anh ta không có ngôn ngữ lập trình với ý định xử lý ngoại lệ.


Nhưng nó thực sự có vấn đề gì trong các dòng ném ngoại lệ?
Simon Forsberg

5
@ SimonAndréForsberg: vâng, đúng vậy. Hãy nghĩ rằng "thro" có tác dụng phụ khi nó tăng bộ đếm toàn cầu khi nó được gọi (điều đó sẽ không thay đổi các đường dẫn có thể thông qua mã). Kết quả có thể xảy ra của bộ đếm đó là 0 đến 7, vì vậy điều này chứng tỏ rằng CC ít nhất là 8.
Doc Brown

Bạn có nói rằng plugin số liệu tôi đang sử dụng đang báo cáo giá trị không chính xác cho mainphương thức không?
Simon Forsberg

@ SimonAndréForsberg: tốt, tôi không biết plugin số liệu của bạn, nhưng 2 rõ ràng không phải là 8.
Doc Brown

Có một liên kết đến plugin số liệu trong câu hỏi của tôi ....
Simon Forsberg

6

Là 'người khác', tôi sẽ trả lời ở đây, và chính xác về những gì tôi nói (điều mà tôi không đặc biệt chính xác với các công thức khác).

Sử dụng ví dụ mã ở trên, tôi tính độ phức tạp chu kỳ là 8 và tôi có các nhận xét trong mã để hiển thị cách tôi tính toán điều đó. Để mô tả các đường dẫn, tôi sẽ xem xét một vòng lặp thành công thông qua tất cả các thro()cuộc gọi dưới dạng 'đường dẫn mã' chính '(hoặc' 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) {
  }
}

Vì vậy, tôi đếm 8 đường dẫn mã trong phương thức chính này, mà theo tôi là Độ phức tạp theo chu kỳ là 8.

Theo thuật ngữ Java, mỗi cơ chế để thoát một hàm tính đến mức độ phức tạp của nó, do đó, một phương thức có trạng thái thành công và, ví dụ, có thể có tới 3 ngoại lệ, có 4 đường dẫn thoát được ghi lại.

Độ phức tạp của một phương thức gọi hàm như vậy là:

CC(method) = 1 + sum (methodCallComplexity - 1)

Tôi nghĩ rằng những điều khác cần xem xét, là theo tôi, catchmệnh đề này không đóng góp vào sự phức tạp của phương thức, catchnó chỉ đơn giản là mục tiêu của một throwsnhánh và do đó, một khối bắt là mục tiêu của nhiều throws đếm 1 lần cho mỗi throw, và không chỉ một lần cho tất cả mọi thứ.


Bạn có đang đếm các nhánh có thể cho OutOfMemoryExceptions không? Ý tôi là về mặt giáo dục, chúng có thể gây ra các nhánh mã, nhưng không ai đếm được chúng vì chúng làm loãng tính hữu dụng của số liệu.
Telastyn

Không, tôi không ... và bạn đúng, nhưng, trong bối cảnh của cuộc tranh luận này, tôi chỉ tính các ngoại lệ mà phương thức được tuyên bố là ném. Ngoài ra, nếu một phương thức khai báo ba ngoại lệ, nhưng mã callinch thực hiện catch (Throwable t) {...thì tôi đoán nó không quan trọng bằng bao nhiêu ngoại lệ mà nó tuyên bố ném.
rolfl
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.