Basic Rules(2)
이 룰은 개발자가 적용할만한 좋은 예들로 구성되어있다.
UselessOperationOnImmutable
이뮤터블객체들(String, BigDecimal 또는 BigInteger 등)에서의 연산(operation)은 스스로를 변경하지 못한다. 이 연산의 결과는 새로운 객체로 생성되어 반환된다. 이런 객체의 연산의 결과가 무시될 경우 에러로 인식한다.
*이뮤터블 객체(Immutable Objects) 한번 만들어진 객체는 변경되지 않으며, 변형이 발생할 때는 새로운 객체를 만든다.
import java.math.*; class Test { void method1() { BigDecimal bd=new BigDecimal(10); bd.add(new BigDecimal(5)); // 연산 결과가 무시된다, } void method2() { BigDecimal bd=new BigDecimal(10); bd = bd.add(new BigDecimal(5)); // 연산 결과가 반영된다. } }
MisplacedNullCheck
잘못된 위치의 null 체크하는 룰. 기본적으로 변수가 null일 경우 변수를 사용할 경우 NullPointerException이 발생하며, 이 룰은 null 체크가 필요 없거나, 잘못된 null 체크에서 발생한다.
public class Foo { void bar() { //a가 null일 경우 NullPointerException이 발생하며 //a가 null이 아닐 경우 equals가 실행됨으로 a != null은 불필요한 체크이다. if (a.equals(baz) && a != null) {} } } public class Foo { void bar() { //a가 null일 경우 NullPointerException이 발생해야하며 equals는 작동하지 않아야한다. //그러므로 a == null 과 같은 체크는 잘못된 null 체크이다. if (a.equals(baz) || a == null) {} } }
UnusedNullCheckInEquals
equals 메소드 사용 시에는 해당 객체의 null 체크 후에 사용하는 것이 좋으며, null이 아닌 객체의 equals 를 사용하는 방법이 null일지 아닐지 모르는 다른 객체에 equals 메소드로 null 아닌 객체를 전달하는 것보다 나은 방법이다.
public class Test { public String method1() { return "ok";} public String method2() { return null;} public void method(String a) { String b; /* method1()이 null일 수 있지만 a가 null이 아니라는 것을 확실하다면 a.equals(method1())이 더 나은 방법이다. */ //a객체가 null이 아닌 것은 확실하지만 //method1()은 null인지 아닌지 불분명함으로 //다음은 룰 위반이다. if (a!=null && method1().equals(a)) { ... } //equals에 전달된 a가 null인지 아닌지 모르는 상태이고, //mehtod1()이 null 이 아닌 상태로 equlas가 실행되었다. //그러므로 룰 위반이 아니다. if (method1().equals(a) && a != null) { ... } //a의 null체크와 method1의 equlas가 별개의 조건으로 //룰 위반이 아니다. if (a!=null && method1().equals(b)) { ... } //a의 null체크와 문자열의 equlas가 별개의 조건으로 //룰 위반이 아니다. if (a!=null && "LITERAL".equals(a)) { ... } //a의 null 체크를 하였고 //null이 아닌 a에 equals 사용하였음으로 룰 위반이 아니다. if (a!=null && !a.equals("go")) { a=method2(); //a는 null이지만 null이 아닌 method1의 equals에 전달되었음으로 //다음은 룰 위반이 아니다. if (method1().equals(a)) { ... } } } }
AvoidThreadGroup
java.lang.ThreadGroup 사용을 피하라. 비록 이것이 스레드 환경에서 사용하도록 의도되었다 하더라도, 이것은 스레드에 안전하지 않은 메소드를 포함한다.
public class Bar { void buz() { ThreadGroup tg = new ThreadGroup("My threadgroup") ; tg = new ThreadGroup(tg, "my thread group"); tg = Thread.currentThread().getThreadGroup(); tg = System.getSecurityManager().getThreadGroup(); } }
BrokenNullCheck
|| 대신에 &&를 사용하거나 반대로 && 대신에 ||을 사용하여 잘못된 null 체크를 할 경우 NullPointerException이 발생한다.
class Foo { String bar(String string) { // &&를 사용해야한다. // ||를 사용할 경우 string이 null일 수 있다. if (string!=null || !string.equals("")) return string; // ||를 사용해야한다. // &&를 사용할 경우 string.equals는 NullPoiterException을 발생시킨다. if (string==null && string.equals("")) return string; } }
BigIntegerInstantiation
이미 존재하는 다음과 같은 BigInteger 인스턴스들은 생성하지 않는다.
Java 1.2이상: BigInteger.ZERO, BigInteger.ONE
Java 1.5이상: BigInteger.TEN, BigDecimal (BigDecimal.ZERO, BigDecimal,ONE, BigDecimal.TEN)
public class Test { public static void main(String[] args) { //BigInteger.ONE을 사용 BigInteger bi=new BigInteger(1); //BigInteger.ZERO를 사용 BigInteger bi2=new BigInteger("0"); //BigInteger.ZERO를 사용 BigInteger bi3=new BigInteger(0.0); BigInteger bi4; //BigInteger.ZERO를 사용 bi4=new BigInteger(0); } }
AvoidUsingOctalValues
8진수형 변수값은 사용하지말자.Java의 8진수 값은 0로 시작하는 integer 값이다.
public class Foo { int i = 012; // i는 12가 아닌 10이다 int j = 010; // j는 10이 아닌 8이다. k = i * j; // k는 120이 아닌 80이다. }
AvoidUsingHardCodedIP
하드 코딩된 IP가 포함된 응용프로그램은 특정 케이스에서 배포가 불가능한 경우가 있다. 그러므로, IP를 코드상 하드코딩하지말자!
public class Foo { String ip = "127.0.0.1"; // 진짜 나쁜 코드 }
CheckResultSet
ResultSet의 네비게이션 메소드(navication method)들 next, previous, first, last을 사용할 경우 언제나 return 값을 확인해야한다. 실제로, 이런 메소드들이 'false'를 돌려줄 경우, 프로그래머는 이에대한 처리를 해야한다.
//부적절한 코드 Statement stat = conn.createStatement(); ResultSet rst = stat.executeQuery("SELECT name FROM person"); rst.next(); // 만약 false를 반환한다면 어떻게 하지??? String firstName = rst.getString(1); //적절한 코드 Statement stat = conn.createStatement(); ResultSet rst = stat.executeQuery("SELECT name FROM person"); if (rst.next()) { String firstName = rst.getString(1); } else { // 에러에 대한 로그 처리와 같은 최소한의 처리를 할 수 있다. }
AvoidMultipleUnaryOperators
복합 단항 연산자 (multiple unary operators)들을 사용할 경우 버그가 발생되거나, 혼란 스럽게 할 수 있다. 이런 사용이 버그가 없도록 확인하거나, 더욱 심플한 표현을 고려해야한다.
// 오자 버그들, 불필요한 복잡성 및 혼동 int i = - -1; int j = + - +1; int z = ~~2; boolean b = !!true; boolean c = !!!true; // 더 나은 방법들: int i = 1; int j = -1; int z = 2; boolean b = true; boolean c = false; // 그냥 머리만 아픈 코드 int i = ~-2; int j = -~7;
EmptyInitializer
빈 초기화를 경고하는 룰
public class Foo { static {} // 왜? {} // 다시한번, 왜? }
해당 URL: http://pmd.sourceforge.net/pmd-4.2.6/rules/basic.html