1. Nulls와 Optionals
Bad Practice: 메서드에서 바로 null을 리턴하는 건 NPE를 유발할 수 있습니다.
public String getString() {
return null;
}
Good Practice: null에 대한 명확한 핸들링과 에러 방지를 위해 Optional을 사용합니다.
public Optional<String> getString() {
return Optional.empty();
}
2. String.valueOf()로 String 변환
Bad Practice: '+' 연산자를 사용해 문자열을 합칩니다.
double d = 3.14525;
String s = "" + d;
Good Practice: 내장 메서드를 활용합니다.
double d = 3.14245;
String s = String.valueOf(d);
3. array를 복사할 때 Arrays.copyOf()
Bad Practice: 정석적으로 array를 복사합니다.
int[] sourceArray = {1, 2, 3, 4, 5};
int[] targetArray = new int[source.length; i++];
for (int i = 0; i < sourceArray.length; i++) {
targetArray[i] = sourceArray[i];
}
Good Practice: Arrays.copyOf() 메서드를 사용합니다.
int[] sourceArray = {1, 2, 3, 4, 5};
int[] targetArray = Arrays.copyOf(sourceArray, sourceArray.length);
4. 컬렉션이 비어있는지 체크하기 위해 isEmpty()
Bad Practice: length()나 size()로 string이나 컬렉션이 비어있는지 체크합니다.
String text = "Hello, World!";
if (text.length() == 0) {
// Do something
}
Good Practice: isEmpty()로 string이나 컬렉션이 비어있는지 체크합니다.
String text = "Hello, World!";
if (text.isEmpty()) {
// Do something
}
5. Concurrent Modification Exception 방지
Bad Practice: 리스트를 순회하고 있는 동안 요소를 제거하여 ConcurrentModificatoinException을 일으킵니다.
List<String> words = new ArrayList<>();
words.add("A");
words.add("B");
words.add("C");
for (String word : words) {
if (word.equals("A")) {
words.remove(word);
}
}
Good Practice: iterator remove 메서드나 removeIf() 메서드를 사용합니다.
List<String> words = new ArrayList<>();
words.add("A");
words.add("B");
words.add("C");
Iterator<String> iterator = words.iterator();
while (iterator.hasNext()) {
String word = iterator.next();
if (word.equals("A")) {
iterator.remove();
}
}
6. 정규표현식 사전 컴파일
Bad Practice: 런타임 시에 정규표현식을 컴파일합니다.
String text = "Hello, World!";
if (text.matches("Hello.*")) {
System.out.println("Matches!");
}
String replaced = text.replaceAll("\\s", "");
Good Practice: 정규표현식을 사전컴파일하고 재사용합니다.
final Pattern PATTERN1 = Pattern.compile("Hello.*");
final Pattern PATTERN2 = Pattern.compile("\\s");
String text = "Hello, World!";
if (PATTERN1.matcher(text).matches()) {
System.out.println("Matches!");
}
String replaced = PATTERN2.matcher(text).replaceAll("");
7. 검색 전 데이터 존재 여부를 확인하지 않기
Bad Practice: 객체를 가져오기 전 map에 id가 있는지 미리 확인합니다. 존재하지 않는다면 null 값을 반환하기 때문에 미리 체크하는 것은 불필요합니다.
public static String findNameById(Map<Integer, String> idNameMap, int id) {
if (idNameMap.containsKey(id)) {
return idNameMap.get(id);
} else {
return "Unknown";
}
}
Good Practice: 바로 map에서 가져온 후 null인지 아닌지 체크하여 존재 여부를 확인합니다.
public static String findNameById(Map<Integer, String> idNameMap, int id) {
String name = idNameMap.get(id);
if (name != null) {
return name;
} else {
return "Unknown";
}
}
8. 배열의 효율적인 변환
Bad Practice:
- 리스트의 사이즈가 먼저 계산된 후 새로운 배열이 생성됩니다.
- 큰 컬렉션일 수록 성능에 영향을 미칠 수 있습니다.
List<String> stringList = new ArrayList<>();
stringList.add("apple");
stringList.add("banana");
stringList.add("orange");
String[] array = stringList.toArray(new String[stringList.size()]);
Good Practice:
- 빈 배열과 함께 toArray 메서드가 호출됩니다.
- 리스트의 크기를 계산할 필요가 없으며 toArray 메서드가 내부적으로 배열 크기를 조정할 수 있으므로 성능이 향상되고 코드가 깨끗해집니다.
List<String> stringList = new ArrayList<>();
stringList.add("apple");
stringList.add("banana");
stringList.add("orange");
String[] array = stringList.toArray(new String[0]);
9. 기본 메서드 사용
Bad Practice: logError와 같은 새로운 메서드를 인터페이스에 추가해야 하는 경우 모든 구현 클래스를 수정해야 하므로 코드 관리 문제가 발생할 수 있습니다.
interface Logger {
void log(String message);
}
class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to file: " + message);
}
}
class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to file: " + message);
}
}
Good Practice: 인터페이스가 기본 메서드를 정의하여 이 메서드는 로그 오류에 대한 기본 구현을 제공합니다. 구현 클래스는 수정할 필요 없이 이 기본 구현을 자동으로 상속합니다.
interface Logger {
default void log(String message) {
System.out.println("Logging to file: " + message);
}
}
class FileLogger implements Logger {
@Override
public void log(String message);
}
class ConsoleLogger implements Logger {
@Override
public void log(String message);
}
10. Date/Time API 사용
Bad Practice: 레거시 Date 클래스를 사용합니다.
- 이 클래스는 변형 가능성, 메서드 명확성 부족 등 다양한 문제가 있습니다.
- getYear(), getMonth()와 같은 이 클래스의 대부분의 메서드는 사용되지 않습니다.
import java.util.Date;
public class DateUtil {
public static void main(String[] args) {
Date currentDate = new Date();
System.out.println("Current date: " + currentDate);
}
}
Good Practice: Date/Time API를 사용합니다.
import java.time.LocalDate;
public class DateUtil {
public static void main(String[] args) {
LocalDate currentDate = LocalDate.now();
System.out.println("Current date: " + currentDate);
}
}
11. 제네릭 사용
Bad Practice: 다른 타입의 데이터가 리스트에 혼합되어 저장됩니다. 런타임 에러를 유발할 수 있습니다.
ArrayList list = new ArrayList();
list.add(10);
list.add("Hello");
Good Practice: 타입의 안정성을 보장하는 제네릭을 사용합니다.
ArrayList list = new ArrayList<>();
list.add(10);
// list.add("Hello"); // Compile-time error: incompatible types
출처
https://levelup.gitconnected.com/15-11-mistakes-every-java-developer-must-avoid-today-ccd7e681a970