'SimplifyBooleanReturns'에 해당되는 글 1건



ConstructorCallsOverridableMethod

우선순위 : 1

영어 실력이 그지같아서  번역이 힘드네요…원문 적고 설명은 샘플 밑에 부연 설명으로 대신하겠습니다.

마지막 줄만 설명하자면 일반적인 제어의 흐름을 따르는 메소드 호출을 하라는 것인데 예를들어

생성자인 Foo()에서 public 메소드인 buz()를 호출하는 private 메소드 bar()를 호출하는 것과 같이 비비 꼬아놓으면

문제의 소지가 있다는 말입니다.

 

원문

Calling overridable methods during construction poses a risk of invoking methods on an incompletely constructed object and can be difficult to debug. It may leave the sub-class unable to construct its superclass or forced to replicate the construction process completely within itself, losing the ability to call super(). If the default constructor contains a call to an overridable method, the subclass may be completely uninstantiable. Note that this includes method calls throughout the control flow graph – i.e., if a constructor Foo() calls a private method bar() that calls a public method buz(), this denotes a problem.

 

샘플 코드

SeniorClass

JuniorClass

 

 

부연 설명

위 샘플 코드를 직접 돌려보면 결과가 다음과 같이 나옵니다.

SeniorClass.constructor
Exception in thread “main” JuniorClass.toString
java.lang.NullPointerException
at JuniorClass.toString(JuniorClass.java:12)
at SeniorClass.<init>(SeniorClass.java:5)
at JuniorClass.<init>(JuniorClass.java:4)
at PMDTestMain.main(PMDTestMain.java:10)

스택트레이스를 따라가보면 JuniorClass의 생성자 > SeniorClass의 생성자 > JuniorClass의 toString 순으로

호출 되고 있습니다. extends SeniorClass로 인해 이미 SeniorClass의 toString은 JuniorClass의 toString으로

바뀐 상태입니다. 결국 super()를 호출한 시점에서 벌써 JuniorClass의 toString이 호출되고 있으나

이 시점에는 아직 name에 값이 할당되기 전이기 때문에 위와같이 NullPointerException이 발생하게 됩니다.


LocalVariableCouldBeFinal

우선순위 : 3

지역변수가 최초 값 할당 이후 값이 변경하지 않는다는 것을 보장하기 위해서

final 변수로 지정할 수 있다.

 

샘플 코드

 

 

부연 설명

만일 메소드 내의 특정 지역변수가 메소드의 처리 과정 내에서 그 값이 변하면 안되는 경우에는

실수에 의한 값 변경을 막기 위해서 final로 사용하는 것도 좋은 방법이라는 의미입니다.

아시다시피 final 변수에 값을 할당하게 되면 컴파일 시에 에러가 발생하기 때문에 쉽게 문제를 발견할 수 있게 됩니다.


AvoidReassigningParameters

우선순위 : 2

메소드에 전달된 파라미터를 직접 재할당하는 것은 피해야 한다.

임시 지역변수를 이용하여 값을 변경하는 것이 좋다.

 

샘플 코드

 

부연 설명

JAVA에서는 매개변수를 전달할 경우 primitive 타입은 변수 값의 복사본을 전달하지만 Object 타입을 전달할 경우

복사본이 아닌 참조값(변수가 저장된 메모리의 주소)를 넘기게 됩니다.

따라서 매개변수에 직접 새로운 값을 할당 할 경우 사실상 primitive 타입을 받은 경우에는 심각한 문제가 발생하지는

않습니다. 다만 코드가 길어질 경우 ‘분명히 X값을 넘겼는데 왜 Y’값으로 바뀌었지?’ 하는 혼란이 생길 수 있습니다.

하지만 Object 타입의 경우는 문제가 심각합니다. 전달받은 쪽에서 값을 변경하면 전달해준 쪽의 값도 같이 바뀌기 때문에…

따라서 특별한 목적이 있지 않는 한 전달받은 매개변수를 직접 수정하는 일은 없어야 합니다.

 

연습

결과

paramTest(할당 전) : strList.size = 4

paramTest(할당 전) : strItem = TEST1

paramTest(할당 전) : strItem = TEST2

paramTest(할당 전) : strItem = TEST3

paramTest(할당 전) : strItem = LOCALTEST4

paramTest(할당 후) : strList.size = 3

paramTest(할당 후) : strItem = LOCALTEST1

paramTest(할당 후) : strItem = LOCALTEST2

paramTest(할당 후) : strItem = LOCALTEST3

paramTest(할당 전) : str = STR_TEST1

paramTest(할당 후) : str = LOCAL_STR_TEST1

main : strList.size = 4

main : strItem = TEST1

main : strItem = TEST2

main : strItem = TEST3

main : strItem = LOCALTEST4

main : str = STR_TEST1



SimplifyBooleanReturns

우선순위 : 3

boolean 값을 리턴하게 될 때는 불필요한 분기문(if-else)을 사용하지 말아라.

대신에 조건을 테스트하는 문장 바로 리턴해도 된다.

샘플 코드

 

부연설명

추후 따로 설명을 하겠지만 if문이 늘어나면 Cyclomatic Complexity라고 하여 복잡성 지표가 올라가게 됩니다.

이는 코드의 가독성을 떨어뜨리고 이해를 어렵게 하는 원인이 되어 품질 관리에서는 특정 점수 이하로 유지하도록

하고 있습니다. (간단하게 복잡도 = 분기문 갯수 + 1이라고 생각하시면 됩니다.)

이러한 이유로 if문은 가능한한 사용하지 않는쪽으로 코딩을 하시는 것이 좋습니다.

블로그 이미지

마즈다

이제 반백이 되었지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

댓글을 달아 주세요