एक ही विधि को कई बार कॉल करने पर साइक्लोमैटिक जटिलता


12

कोड समीक्षा में एक प्रश्न के लिए धन्यवाद, मैं थोड़ा असहमति (जो अनिवार्य रूप से कुछ सीखने का अवसर है) के बारे में मिला, जो कि नीचे दिए गए कोड के लिए वास्तव में साइक्लोमैटिक जटिलता है।

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

ग्रहण में इस कोड को लिखने और ग्रहण मेट्रिक्स प्लगइन का उपयोग करते समय , यह मुझे बताता है कि मुख्य विधि के लिए मैककेब साइक्लोमैटिक जटिलता 2 है, और throविधि के लिए यह 2 कहता है।

हालांकि, कोई और मुझे बताता है कि throकई बार कॉल करने की जटिलता है number of calls * method complexity, और इसलिए दावा है कि मुख्य विधि की जटिलता 7 * 14 = 14 है।

क्या हम अलग-अलग चीजों को माप रहे हैं? क्या हम दोनों सही हो सकते हैं? या यहाँ वास्तविक चक्रीय जटिलता क्या है?


5
फ़ंक्शन का सीसी दो है, क्योंकि केवल दो रास्ते हैं। कार्यक्रम का सीसी अधिक है। यह अंधेरे में एक पूरी तरह से छुरा है, लेकिन मुझे लगता है कि कोड विश्लेषण सॉफ्टवेयर प्रत्येक फ़ंक्शन को एक ही बार में पूरे जटिल एप्लिकेशन के सीसी की गणना करने की क्षमता के कारण एक अलग ब्लैक बॉक्स के रूप में लेता है।
फॉशी

@Phoshi यदि आप लिखते हैं कि एक उत्तर के रूप में और (यदि संभव हो तो) लिंक प्रदान करें जिससे पता चलता है कि दोनों का अलगाव है, तो मैं ख़ुशी से उस उत्तर को स्वीकार करूँगा।
साइमन फोर्सबर्ग

यदि आप सीसी माप में संभावित अपवादों के कारण होने वाले सभी रास्तों को गिनते हैं, तो भगवान उस व्यक्ति की मदद करते हैं जिसने नंबर पाने के लिए कुछ तुच्छ कोड को फिर से लाने पर सवाल पूछा था। 10.
मैटनज़

जवाबों:


9

जब मैं इस को सही ढंग से समझ में आया, cyclomatic जटिलता की main8 - कोड के माध्यम से रैखिक स्वतंत्र रास्तों की संख्या है। आपको या तो सात लाइनों में से एक पर अपवाद मिलता है, या कोई नहीं, लेकिन कभी भी एक से अधिक नहीं। उस संभव "अपवाद बिंदुओं" में से प्रत्येक कोड के माध्यम से बिल्कुल एक अलग पथ से मेल खाता है।

मुझे लगता है कि जब मैकाबे ने उस मीट्रिक का आविष्कार किया था, तो उसके पास प्रोग्रामिंग भाषाओं को ध्यान में रखते हुए अपवाद नहीं था।


लेकिन क्या यह वास्तव में मायने रखता है कि कौन सी रेखाएं अपवाद को फेंकती हैं?
साइमन फोर्सबर्ग

5
@ साइमनएंड्रेफोर्सबर्ग: हां, यह करता है। "थ्रो" के साइड इफेक्ट होने के बारे में सोचें जहां यह कहा जाता है जब यह एक वैश्विक काउंटर को बढ़ाता है (जो कोड के माध्यम से संभव पथ नहीं बदलेगा)। उस काउंटर के संभावित परिणाम तब 0 से 7 हैं, इसलिए यह साबित होता है कि सीसी कम से कम 8. है
डॉक्टर ब्राउन

क्या आप कहेंगे कि मैं जिस मैट्रिक्स प्लगइन का उपयोग कर रहा हूं , वह विधि के लिए गलत मान बता रहा है main?
साइमन फोर्सबर्ग

@ साइमनएंड्रेफोर्सबर्ग: ठीक है, मुझे आपके मेट्रिक्स प्लगइन का पता नहीं है, लेकिन 2 स्पष्ट रूप से नहीं है। 8.
Doc Brown

मेरे प्रश्न में मेट्रिक्स प्लगइन का लिंक है ....
साइमन फोर्सबर्ग

6

'दूसरे आदमी' होने के नाते, मैं यहां जवाब दूंगा, और जो मैं कहता हूं उसके बारे में सटीक हूं (जो कि मैं अन्य फॉर्मूलों के साथ विशेष रूप से सटीक नहीं था)।

ऊपर दिए गए कोड उदाहरण का उपयोग करते हुए, मैं 8 के रूप में साइक्लोमैटिक जटिलता की गणना करता हूं, और कोड में टिप्पणी करता हूं कि मैं कैसे गणना करता हूं। रास्तों का वर्णन करने के लिए मैं के माध्यम से एक सफल पाश पर विचार करेंगे सभीthro() 'मुख्य' 'कोड पथ के रूप में कॉल' (या 'सी.पी. = 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) {
  }
}

तो, मैं इस मुख्य विधि में, कोड पथों की गणना करता हूं, जो कि, मेरे लिए atic का साइक्लोमैटिक कॉम्प्लेक्सिटी है।

जावा के संदर्भ में, एक समारोह से बाहर निकलने के लिए प्रत्येक तंत्र इसकी जटिलता को गिना जाता है, इसलिए, एक विधि जिसमें एक सफलता-राज्य है, और, फेंकता है, उदाहरण के लिए, संभवतः 3 अपवादों तक, 4 प्रलेखित निकास पथ हैं।

इस तरह के एक फ़ंक्शन को कॉल करने वाली विधि की जटिलता है:

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

मुझे लगता है कि अन्य बातों पर विचार करना है, क्या मेरी राय में, यह catchखंड विधि की जटिलता में योगदान नहीं देता है, catchयह केवल एक throwsशाखा का लक्ष्य है , और इस प्रकार एक पकड़ ब्लॉक है जो कि कई बार throws मायने रखता है 1 बार का लक्ष्य प्रत्येक के लिए throw, और हर चीज के लिए सिर्फ एक बार नहीं।


क्या आप OutOfMemoryException के लिए संभावित शाखाओं की गिनती कर रहे हैं? मेरा अभिप्राय यह है कि वे कोड शाखाओं का कारण बन सकते हैं, लेकिन कोई भी उन्हें गिनता नहीं है क्योंकि वे मीट्रिक की उपयोगिता को कम करते हैं।
तेलेस्टिन

नहीं, मैं नहीं हूं ... और आप सही हैं, लेकिन, इस तर्क के संदर्भ में, मैं केवल अपवादों को गिना जाता हूं कि विधि को फेंकने के लिए घोषित किया गया है। इसके अलावा, अगर कोई विधि तीन अपवादों की घोषणा करती है, लेकिन कॉलिंच कोड एक catch (Throwable t) {...तत्कालीन करता है, तो मुझे लगता है कि इससे कोई फर्क नहीं पड़ता कि कितने अपवाद इसे फेंकने की घोषणा करते हैं।
रॉल्फल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.