PMD
Programming Mistake Detector
전자정부 표준 프레임워크
😎 전자정부 표준프레임워크 표준 Inspection 룰셋
PMD를 이용한 Code Inspection 시 기준이 되는 요소는 룰이며, 전자정부 표준프레임워크에서는 PMD가 제공하는 수 많은 룰 중에서 기본이 될 만한 것들을 간추려 전자정부 표준프레임워크 표준 Inspection 룰셋이라는 이름으로 구성하였다.
전자정부 표준프레임워크의 표준 Inspection 룰셋은 다음의 표와 같은 39개의 룰들로 구성된다. 개별 룰에 대한 상세한 설명은 전자정부 표준 inspection 룰셋을 참고합니다.
번호 | 룰 이름 | 설명 |
01 | EmptyCatchBlock | 내용이 없는 Catch Block이 존재 |
02 | EmptyIfStmt | 빈 if 구문의 사용을 피하도록 함 |
03 | EmptyWhileStmt | 빈 while 구문이 사용되었음 |
04 | EmptyTryBlock | 내용이 없는 try 블록이 존재함 |
05 | EmptyFinallyBlock | 내용이 없는 finally 블록이 존재함 |
06 | UnnecessaryConversionTemporary | 기본 데이터 타입을 String으로 변환할 때 불필요한 임시 변환 작업을 피하도록 함 |
07 | EmptyStatementNotInLoop | 필요없는 문장 (;)이 있음 |
08 | WhileLoopsMustUseBraces | 중괄호없이 사용된 while문의 사용은 바람직하지 못한 코딩 습관임 |
09 | AssignmentInOperand | 피연산자내에 할당문이 사용됨. 해당 코드를 복잡하고 가독성이 떨어지게 만듬 |
10 | UnnecessaryParentheses | 괄호가 없어도 되는 상황에서 불필요한 괄호를 사용할 경우 마치 메소드 호출처럼 보여서 소스 코드의 가독성을 떨어뜨릴 수 있음 |
11 | SimplifyBooleanExpressions | boolean 사용 시 불필요한 비교 연산을 피하도록 함 |
12 | SwitchStmtsShouldHaveDefault | Switch구문에는 반드시 default label이 있어야 함 |
13 | AvoidReassigningParameters | 넘겨받는 메소드 parameter 값을 직접 변경하는 코드 탐지. |
14 | FinalFieldCouldBeStatic | final field를 static으로 변경하면 overhead를 줄일 수 있음 |
15 | EqualsNull | null 값과 비교하기 위해 equals 메소드를 사용하였음 |
16 | SimpleDateFormatNeedsLocale | SimpleDateFormat 인스턴스를 생성할때 Locale 을 지정하는 것이 바람직함 |
17 | ImmutableField | 생성자를 통해 할당된 변수를 Final로 선언하지 않았음 |
18 | AssignmentToNonFinalStatic | static 필드의 안전하지않은 사용 가능성이 존재 |
19 | AvoidSynchronizedAtMethodLevel | mothod 레벨의 synchronization 보다 block 레벨 synchronization 을 사용하는 것이 바람직함 |
20 | AbstractClassWithoutAbstractMethod | Abstract Class내에 Abstract Method가 존재하지 않음 |
21 | UncommentedEmptyMethod | 빈 메소드에 빈메소드임을 나타내는 주석을 추가할 것 |
22 | AvoidConstantsInterface | Interface는 클래스의 behavior 을 구현하는 데에만 사용해야 함 |
23 | DuplicateImports | import문이 중복 선언 되었음 |
24 | ImportFromSamePackage | 동일 패키지에 있을 때는 import문을 사용할 필요가 없음 |
25 | SystemPrintln | System.out.print 가 사용됨. 전용 로거를 사용할 것을 권장 |
26 | VariableNamingConventions | final이 아닌 변수는 밑줄을 포함할 수 없음 |
27 | MisleadingVariableName | non-field 이름이 m_ 으로 시작함' |
28 | AvoidArrayLoops | 배열의 값을 루프문을 이용하여 복사하는 것 보다, System.arraycopy() 메소드를 이용하여 복사하는 것이 효율적이며 수행 속도가 빠름 |
29 | UnnecessaryWrapperObjectCreation | 불필요한 Wrapper Object가 생성되었음. 탐지된 코드는 삭제하고, 별도의 parse관련 전용 메소드 사용을 권장 |
30 | AvoidThrowingRawExceptionTypes | 가공되지 않은 Exception을 throw하는 것은 비추천 |
31 | AvoidThrowingNullPointerException | NullPointerException을 throw하는 것은 비추천 |
32 | StringInstantiation | 불필요한 String Instance를 생성하는 코드를 탐지. 간단한 형태의 코드로 변경 필요 |
33 | StringToString | String 객체에서 toString()함수를 사용하는 것은 불필요함. 해당 코드 제거 필요 |
34 | InefficientStringBuffering | StringBuffer 함수내에서 비문자열 연산 이용하여 직접 결합하는 코드 사용을 탐지. append 메소드 사용을 권장 |
35 | InefficientEmptyStringCheck | 빈 문자열 확인을 위해 String.trim().length() 을 사용하는 것은 피하도록 함. whitespace/Non-whitespace 확인을 위한 별도의 로직 구현을 권장 |
36 | UselessStringValueOf | String 을 append 할 경우, String.valueOf 함수를 사용할 필요 없음 |
37 | UnusedPrivateField | 사용되지 않는 Private field의 탐지 |
38 | UnusedPrivateMethod | 사용되지 않는 Private Method 선언을 탐지 |
39 | UnusedFormalParameter | 메소드 선언 내에사용되지 않는 파라미터를 탐지 |
😎 PMD 적용대상 Rule Set
총 10개 룰셋이며, 필수인 39개 룰을 적용합니다.
😎 Basic Rules
대부분의 개발자들이 동의하는 규칙: catch 블록들은 비어있어서는 안되고, equals()를 오버라이딩 할 때 마다 hashCode()를 오버라이드한다.
🙄 EmptyCatchBlock
빈 catch문의 사용을 지양한다. 내용이 없는 Catch Block이 존재. Exception 처리가 안될 수 있음.
수정전
catch (Exception e){
}
수정후
catch (Exception e){
``catch시의 처리내용을 추가할것``
}
🙄 EmptyIfStmt
조건에 해당되는 수행문이 없는 if문의 사용을 지양한다.
수정전
else {
}
수정후
삭제 또는 반대 조건을 이용하여 처리
🙄 EmptyFinallyBlock
finally block이 비어있음
수정전
finally {
}
수정후
빈 블럭 삭제
🙄 EmptyTryBlock
내용이 없는 try 블록이 존재함
수정전
try{
}
수정후
삭제
🙄 EmptyWhileStmt
빈 While 구문이 사용되었음.
수정전
while(true){
}
수정후
삭제
🙄 EmptyStatementNotInLoop
loop 블럭에서 ";" 만 포함한 구문의 사용을 지양한다. (불필요한 세미콜론은 삭제되어야 함)
수정전
while(true){
;
}
수정후
삭제
🙄 UnnecessaryConversionTemporary
기본 데이터(primitive type)를 String으로 변환할 때 불필요한 임시 변환 작업을 피하도록 함
수정전
public String convert(int x) {
// this wastes an object
String foo = new Integer(x).toString();
return foo;}
수정후
public String convert(int x) {
// this is better
return Integer.toString(x);}
😎 Braces Rules
🙄 WhileLoopsMustUseBraces
중괄호({})없이 사용된 while문의 사용은 피하라
수정전
while(isdigit(c)) c = get();
수정후
while(isdigit(c)) {
c = get();
}
😎 Controversial Rules
🙄 AssignmentInOperand
코드를 복잡하게 하고 가독성이 떨어지는 피연산자에 할당하는 것을 지양한다.
수정전
while ( (r = tQuery.fetch() )!= null){
... do something
}
수정후
while (true){
r = tQuery.fetch();
if(r == null){
break;
}
.. do something ..
}
🙄 DuplicateImports
import문이 중복 선언 되었음
수정전
수정후
중복 import 삭제
🙄 UnnecessaryParentheses
괄호가 없어도 되는 상황에서 불필요한 괄호를 사용할 경우 마치 메소드 호출처럼 보여서 소스 코드의 가독성을 떨어뜨릴 수 있음. 이에 불필요한 괄호를 삭제토록 함
수정전
public class Foo {
boolean bar() {
return (true);
}
}
수정후
public class Foo {
boolean bar() {
return true;
}
}
😎 Design Rules
다양한 좋은 디자인 원리 체크, 이를 테면: switch 문장은 default 블록을 갖고 있어야 하고, 심하게 중첩된 if 블록은 피해야 하고, 매개변수들은 재할당되어서는 안되며, 더블(double)이 동일함(equality)과 비교되어서도 안된다.
🙄 AvoidReassigningParameters
파라미터값을 재할당 하지 않는다.
수정전
public int WriteObject(int nShapeId, SHPObject theObject) throws Exception{
nShapeId = m_nRecords++;
}
수정후
public int WriteObject(int nShapeId, SHPObject theObject) throws Exception{
int newShapeId = m_nRecords++;
}
🙄 AvoidSynchronizedAtMethodLevel
“mothod 레벨의 synchronization 보다 block 레벨 synchronization 을 사용하는 것이 바람직함. 새로운 코드가 메소드에 추가되었을때, 메소드 레벨 동기화는 역효과를 일으킨다. 블락레벨 동기화는 동기화가 필요한 코드가 동기화될 수 있도록 도울것이다.”
수정전
protected static synchronized void debug_println(String stText) {
System.out.println(stText);
}
수정후
protected static void debug_println(String stText){
synchronized (stText) {
System.out.println(stText);
}
}
🙄 AssignmentToNonFinalStatic
static 필드의 안전하지않은 사용 가능성
수정전
public static int PK_IDX = 8;
수정후
public static final int PK_IDX = 8;
🙄 EqualsNull
null 값과 비교하기 위해 equals 함수를 사용하였음.
수정전
if (A.equals(null)){
}
수정후
if (A == null){
}
🙄 FinalFieldCouldBeStatic
final field를 Static 으로 변경하면 overhead 를 줄일 수 있음.
수정전
public final int PK_IDX = 8;
수정후
public static final int PK_IDX = 8;
🙄 ImportFromSamePackage
동일 패키지에 있을 때는 import문을 사용할 필요가 없음
수정후
import 삭제
🙄 ImmutableField
생성자에서 Assign된 변수를 Final로 선언하지 않았음
수정전
public class Foo {
private int x; // could be final
public Foo() {
x = 7;
}
}
수정후
public class Foo {
private final int x;
public Foo() {
x = 7;
}
}
🙄 SimpleDateFormatNeedsLocale
SimpleDateFormat 인스턴스를 생성할때 Locale 을 지정하는 것이 바람직함
수정전
SimpleDateFormat sdf = new SimpleDateFormat();
수정후
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss", Locale.KOREA);
🙄 SimplifyBooleanExpressions
boolean 표현에서 불필요한 비교는 사용을 지양한다.
수정전
if (bShell == true)
수정후
if (bShell)
🙄 SwitchStmtsShouldHaveDefault
Switch구문에는 반드시 default label이 있어야 함
수정전
switch(a){
case SeColumnDefinition.TYPE_BLOB:
break;
}
수정후
switch(a){
case SeColumnDefinition.TYPE_BLOB:
break;
default:
.. do Something ..
}
🙄 UncommentedEmptyMethod
Empty Method 가 사용되었음. 의도적으로 Empty Method 를 구현했다면 그에 대항하는 주석을 기재하는 것이 바람직함.
수정전
public static void main(String[] args) {}
수정후
불필요할 경우 삭제, 의도적이면 주석추가
🙄 AbstractClassWithoutAbstractMethod
추상클래스 정의 오류
수정전
Abstract Class내에 Abstract Method가 존재하지 않음
수정후
Class 로 변경
🙄 AvoidConstantsInterface
인터페이스에 상수 적용
수정전
public interface ParserTokens {
public final static short OR=257;
public void method();}
수정후
public interface ParserTokens {
public void method();}
😎 Java Logging Rules
🙄 SystemPrintln
개발 시 디버그 작업을 위해 사용한 System.out.println()문이 남아 있음. 불필요한 System.out.println()문은 시스템에 부하를 발생 시킨다.
수정전
System.out.println("SHPType = " + theInfo.m_nShapeType);
수정후
protected static Logger logger = Logger.getLogger(Main.class.getName());
logger.info("SHPType = " + theInfo.m_nShapeType);
😎 Naming Rules
표준 자바 네이밍 규약을 위한 테스트: 변수 이름들은 너무 짧아서는 안된다; 메소드 이름은 너무 길어서는 안된다; 클래스 이름은 대문자로 시작해야 하고, 메소드와 필드 이름들은 소문자로 시작해야 한다.
🙄 MisleadingVariableName
변수명에 잘못된 prefix 사용. non-field 이름이 m_ 으로 시작하지 말아야 함
수정전
public void bar(String m_baz) { // 메소드명이므로 X
int m_boz = 42; // 지역변수이므로 X
}
수정후
public void bar(String baz) {
int boz = 42;
}
🙄 VariableNamingConventions
다음 2가지 경우 중 하나입니다.
-
final 변수 이름이 대문자가 아님.
-
non-final 변수에 underscore 가 포함되어 있음.
수정전
public static final String m_stEnc = "euc-kr";protected FileIO m_theShp = null;
수정후
public static final String ST_ENC = "euc-kr";protected FileIO mTheShp = null;
😎 Optimizaion Rules
🙄 AvoidArrayLoops
배열의 값을 루프문을 이용하여 복사하는 것 보다 System.arraycopy() 메소드를 이용하여 복사하는 것이 효율적이며 수행 속도가 빠름
🙄 UnnecessaryWrapperObjectCreation
불필요한 Wrapper Object가 생성되었음. Parsing 메소드를 직접적 호출하는 것이 바람직함.
수정전
int i;
i = Integer.valueOf(s).intValue(); // this wastes an object
수정후
int i2;
i2 = Integer.parseInt(s); // this is better
😎 Strict Exception Rules
예외 테스트: 메소드는 java.lang.Exception을 던지도록 선언되어서는 안되고, 예외는 플로우 제어에 사용되어서는 안되며, Throwable은 잡혀서는 안된다
🙄 AvoidThrowingRawExceptionTypes
단순히 RuntimeException, Throwable, Exception 또는 Error를 전달하지말고 더욱 명확한 오류 타입들로 전달해야 합니다.
수정전
if (StringUtils.isEmpty(props.getString("smtp.config"))) {
throw new RuntimeException("Bad Configuration for smtp.config");}
수정후
if (StringUtils.isEmpty(props.getString("smtp.config"))) {
throw new BadConfigurationException("smtp.config");}
// Exception 처리를 위한 클래스를 생성합니다.public class BadConfigurationException extends Exception {
public BadConfigurationException (String message) {
... 처리...
}}
🙄 AvoidThrowingNullPointerException
NullPointerException을 throw하는것을 지양한다. 대신 IllegalArgumentException 사용을 고려하라.
수정전
public class Foo {
void bar() {
throw new NullPointerException();
}}
수정후
public class Foo {
void bar() {
throw new IllegalArgumentException();
}}
😎 String and StringBuffer Rules
스트링 관련 작업을 할 때 발생하는 일반적인 문제들 규명. 스트링 리터럴 중복, String 구조체 호출, String 객체에 toString() 호출하기 등.
🙄 StringToString
String object에서 toString() 호출을 지양한다.
수정전
sb.append(" Where pnu = '").append(pnuSgg.toString()).append("';");
수정후
sb.append(" Where pnu = '").append(pnuSgg).append("';");
🙄 InefficientStringBuffering
“StringBuffer 함수에서 nonliteral 을 직접 concatenate 하지 말 것. Nonliteral conatenation 는 별도로 처리할 것.”
수정전
public class Foo {
void bar() {
// Avoid this
StringBuffer sb=new StringBuffer(""tmp = ""+System.getProperty(""java.io.tmpdir""));
}}
수정후
public class Foo {
void bar() {
// use instead something like this
StringBuffer sb = new StringBuffer(""tmp = "");
sb.append(System.getProperty(""java.io.tmpdir""));
}}
🙄 StringInstantiation
필요없는 Instance가 생성되어 있음
수정전
public class Foo {
private String bar = new String("bar");}
수정후
public class Foo {
private String bar = "bar";}
🙄 InefficientEmptyStringCheck
Empty String 을 체크하기 위해 String.trim().length() 을 사용하는 것은 피하도록 함. Character.isWhitespace()를 사용하는 것이 바람직함
수정후
isWhitespace를 이용하여 공백을 체크하는 로직으로 변경처리
🙄 UselessStringValueOf
“String 을 append 할 경우, String.valueOf 함수를 사용할 필요 없음. Valueof() 대신 직접 사용하는 것이 바람직함.”
수정전
return (String.valueOf(obj)+"\n").getBytes();
수정후
return (obj+"\n").getBytes();
😎 Unused Code Rules
결코 읽히지 않은 프라이빗 필드와 로컬 변수, 접근할 수 없는 문장, 결코 호출되지 않는 프라이빗 메소드 등을 찾기
🙄 UnusedFormalParameter
사용하지 않는 파라미터는 메소드의 파라미터에서 제외한다.
수정전
private static Geometry getLineGeometryFromSeShape(GeometryFactory tFactory, int[] parts, int[] subParts, SDEPoint[] points){
// parts 와 subParts 를 사용하지 않음.}
수정후
private static Geometry getLineGeometryFromSeShape(GeometryFactory tFactory, SDEPoint[] points){}
🙄 UnusedPrivateField
사용되지 않는 값이 할당된 private field를 지양한다.
🙄 UnusedPrivateMethod
사용되지 않는 private method 사용을 지양한다.
😝 PMD 룰 적용 방법 (이클립스) 😝
😎 플러그인 설치
이클립스 실행 후
-
Help → Install New Software
-
Add
입력
Name: PMD
Location: http://sourceforge.net/projects/pmd/files/pmd-eclipse/update-site/
대상 이클립스 선택
이후 설치 진행하시면 됩니다.
😝룰셋 등록 😝
-
Window → Preferences
-
PMD → Rule Configuration
-
Clear all 클릭 → 기존 내용을 모두 지움
-
Import rule set 클릭
-
파일선택 ( pmd-rule_전자정부 )
-
Import by Copy 체크 박스 선택
-
OK 버튼 클릭
-
Apply 버튼 클릭
임포트시에 OK 버튼이 활성화 안되는 것은 이클립스 버전이 다르기 때문입니다. 신버전 이클립스를 사용하는경우에는<rule ref="rulesets/basic.xml/UnusedNullCheckInEquals"> 부분을 <rule ref="rulesets/java/basic.xml/UnusedNullCheckInEquals"> 이렇게 변경해야 합니다.
😝 PMD 실행 😝
😎 PMD Check
-
프로젝트 마우스 우클릭
-
PMD → Check Code with PMD
Violations Overview 창에서 PMD 결과를 확인하실 수 있습니다.
Violations Outline 창에서 Error Message 와 Line 을 확인하실 수 있습니다.
😎PMD 해제
PMD로 위반 부분을 모두 수정 하기전에, 빌드를 해야 할 상황이라면 PMD 해제를 합니다.
-
프로젝트 마우스 우클릭
-
PMD → Clear PMD Violation
😝 PMD 룰 제외 방법 😝
😎 Annotation
JDK 1.5 이상에서 사용
전체 룰 적용
// This will suppress all the PMD warnings in this class
@SuppressWarnings("PMD")public class Bar {
void bar() {
int foo;
}}
룰 한개 적용
// This will suppress UnusedLocalVariable warnings in this class
@SuppressWarnings("PMD.UnusedLocalVariable")public class Bar {
void bar() {
int foo;
}}
룰셋 적용
// This will suppress UnusedLocalVariable and UnusedPrivateMethod warnings in this class
@SuppressWarnings("unused")public class Bar {
void bar() {
int foo;
}
private void foobar(){}}
😎 NOPMD
NO PMD
public class Bar {
// 'bar' is accessed by a native method, so we want to suppress warnings for it
private int bar; //NOPMD}
supress warnings
public class Foo {
void bar() {
int x = 2; // TURN_OFF_WARNINGS
}}
'Back-end > JAVA & Spring' 카테고리의 다른 글
[JAVA]파일을 멀티파트로 변환 (0) | 2022.04.18 |
---|---|
[java] 임시 비밀번호 생성 Random / SecureRandom /RandomStringUtils) (0) | 2022.03.03 |
[java]Parameter... 표현 Object... args(동일한 파라메터를 여러개 받을 때, 자동으로 배열처리) (0) | 2021.12.28 |
[Spring] @PathVariable 사용법 (0) | 2021.12.28 |
@RequestParam과 @PathVariable? (0) | 2021.12.28 |
댓글