멤버 변수가 없는 추상 클래스는 인터페이스로 전환되어야 합니다.

Java 8에 default method 기능이 추가되면서, 상속된 필드나 자신이 갖고 있는 필드가 없는 추상 클래스들은 인터페이스로 전환이 가능해졌습니다. 하지만, 이 규칙은 클래스를 API로 사용하려는 라이브러리나 기타 애플리케이션에서는 적용되기 적절하지 않을 수 있습니다. 참고: 이 규칙은 프로젝트의 sonar.java.source의 값이 8보다 낮은 경우(java8) 검사하지 않습니다. 규칙을 어긴 코드 public abstract class Car { public abstract void start(Environment c); public void stop(Environment c) { ...

더보기

하나의 메소드만 갖는 익명 내부 클래스는 람다식으로 교체돼야 합니다

Java 8 이전에는, 클로저를 일부 지원하기위한 유일한 방법은 익명 내부 클래스를 사용하는 것이었습니다. 하지만, 익명 클래스는 구문을 다루기도 어렵고, 불명확해 보입니다. Java 8부터, 익명 내부 클래스의 대안으로 lambdas식이 추가되었습니다. lambdas는 소스코드의 가독성을 높여주는데 크게 도움이 됩니다. 참고: 이 규칙은 프로젝트의 sonar.java.source의 값이 8보다 낮은 경우(java8) 검사하지 않습니다. 규칙을 어긴 코드 myCollection.stream().map(new Mapper<String,String>() { public String map(Stri...

더보기

Statement를 하나만 포함하는 람다는, 이 Statement가 {}(block scope) 안에 있어선 안됩니다.

Statement를 하나만 사용하는 람다를 표현하는 방법은 두 가지가 있지만, 더 잘읽히고 간결한 방법은 정해져있습니다. 참고: 이 규칙은 프로젝트의 sonar.java.source의 값이 8보다 낮은 경우(java8) 자동으로 비활성화됩니다. 규칙을 어긴 코드 x -> {System.out.println(x+1);} (a, b) -> { return a+b; } 규칙을 준수한 해결책 x -> System.out.println(x+1) (a, b) -> a+b // return 문 같은 경우도 없앨 수 있습니다 If you like SONARKUBE, don’t forg...

더보기

@SpringBootApplication" 과 @ComponentScan 어노테이션은 default package 에서 사용되서는 안됩니다.

@ComponentScan 은 애플리케이션 컨텍스트에서 사용 가능한 Spring Beans 를 결정하는 데에 사용됩니다. @ComponentScan 의 basePakcageClasses 또는 basePackages 파라미터를 통해 스캔할 패키지를 설정할 수 있습니다. 두 파라미터가 모두 설정되지 않은 경우, @ComponentScan 은 주석이 달린 클래스의 패키지만을 대상으로 컴포넌트를 스캔합니다. default package 에 속한 클래스에서 @ComponentScan 어노테이션을 사용하는 경우, 전체 클래스패스를 대상으로 스캔합니다. 전체 클래스 패스를 대상으로 컴포넌트 스캔이 진행될 경우 애플리케이션의 시...

더보기

@Controller 클래스에서 @SessionAttributes 를 사용하는 경우 SessionStatus 객체의 setComplete 메소드를 호출해야 합니다.

@SessionAttributes를 사용하는 Spring @Controller는 stateful/multi-post 형식을 처리하도록 설계되었습니다. 이러한 @Controller는 지정된 @SessionAttributes를 사용하여 요청 간에 서버에 데이터를 저장합니다. 해당 데이터는 세션이 끝나면 정리되어야 하지만 @RequestMapping 메서드에서 SessionStatus 객체에 대해 setComplete()가 호출되지 않는 한 Spring 이나 JVM 에서 해당 데이터를 정리할 수 없습니다. SessionStatus 개체는 해당 메서드에 매개 변수로 전달되어야 합니다. 규칙을 어긴 코드 @Control...

더보기

같은 클래스 내의 메소드에서 호환되지 않는 "@Transactional" 메소드를 호출하지 않아야 합니다.

스프링 프록시를 사용할 때, 같은 클래스 내에서 호환되지 않는 다른 “@Transactional” 메소드를 호출하는 경우(this.aMethod() 처럼), 런타임 에러가 발생할 수 있습니다. 이것은 스프링이 오직 메소드의 호출자(caller)만을 보고 있으며, 피호출자(callee)를 위한 적절한 설정을 생성할 수 없기 때문입니다. 그러므로, 아래와 같이 동일한 클래스 내에서 특정한 경우에 대해 메소드가 다른 메소드를 호출해서는 안됩니다. From To non-@Transactional MANDATORY, NESTED, R...

더보기

"list::add"대신 "Streams"과 "collect"을 사용해야 합니다

Stream을 사용하시면 forEach(list::add)나 collect를 사용할 수 있지만, collect를 사용하는게 병렬화 가능하고 thread-safe하기 때문에 더 좋습니다. 규칙을 어긴 코드 List<String> bookNames = new ArrayList<>(); books.stream().filter(book -> book.getIsbn().startsWith("0")) .map(Book::getTitle) .forEach(bookNames::add); // 규칙을 어긴 코드 규칙을 준수한 해결책 List<String> bookNames =...

더보기