Java 8 Optional을 활용한 Null 처리

Null 처리에 대한 고민

프로그램 개발 중 자주 마주치는 문제 중 하나는 Null 처리입니다. 예를 들어, Course 클래스가 List stuList 속성을 가진다고 가정합시다. Student 클래스는 name이라는 속성을 가지고 있습니다. 특정 학생의 이름 길이를 확인하려고 할 때 다음과 같은 코드를 작성할 수 있습니다.

Course course = new Course("수학");
Student s0 = new Student("s0");
Student s1 = new Student(null);
Student s2 = null;
course.addStudent(s0, s1, s2);
int index = 1;

// NullPointerException 발생 가능성
String name = course.getStuList().get(index).getName();
System.out.println(name.length());
위 코드에서 만약 s2가 null이거나 s1의 name이 null인 경우 NullPointerException이 발생합니다. 이를 방지하기 위해 많은 if-else 조건문을 사용해야 합니다.

Optional로 Null 처리하기

Java 8에서는 Null을 더 효과적으로 처리하기 위한 Optional 클래스를 도입했습니다. 이 클래스는 특정 값이 존재하거나 존재하지 않을 수 있는 상황을 단순화하여 처리할 수 있게 해줍니다.

기본적인 Optional 사용법

아래는 Optional 클래스의 기본적인 사용 방법입니다.

Optional<Student> emptyStudent = Optional.empty(); // null 값을 나타내는 Optional 객체
Student student = new Student("s0");
System.out.println(emptyStudent.isPresent()); // false

Optional<Student> nonEmptyStudent = Optional.ofNullable(student); // 비어 있지 않은 Optional 객체
System.out.println(nonEmptyStudent.isPresent()); // true
Student retrievedStudent = nonEmptyStudent.get(); // 내부 값 가져오기

Optional을 활용한 코드 리팩토링

위의 문제를 Optional을 사용하여 해결해 보겠습니다.

Course course = new Course("수학");
Student s0 = new Student("s0");
Student s1 = new Student(null);
Student s2 = null;
course.addStudent(s0, s1, s2);

int index = 1;
Optional<Student> optionalStudent = Optional.ofNullable(course.getStuList().get(index));
String errorMessage = "처리 과정에서 Null 없음";
String name = "";

if (optionalStudent.isPresent()) {
    Optional<String> optionalName = Optional.ofNullable(optionalStudent.get().getName());
    if (optionalName.isPresent()) {
        name = optionalName.get();
        System.out.println(name.length());
    } else {
        errorMessage = "student 객체의 name이 Null입니다.";
    }
} else {
    errorMessage = "student 객체가 Null입니다.";
}
System.out.println(errorMessage);
이제 코드가 조금 더 안전하게 작동합니다.

Optional의 ifPresent와 orElse 메서드

Optional은 추가적으로 유용한 메서드들을 제공합니다.

optionalStudent.ifPresent(student -> System.out.println(student.getName()));
Student defaultStudent = new Student("기본 학생");
Student result = optionalStudent.orElse(defaultStudent);

map 메서드 활용

코드를 더욱 간결하게 만들기 위해 map 메서드를 사용할 수 있습니다.

int index = 0;
String errorMessage = "처리 과정에서 Null 발생";
Optional<Course> optionalCourse = Optional.ofNullable(course);
Optional<String> resultOptional = optionalCourse.map(c -> c.getStu(index)).map(s -> s.getName());
String result = resultOptional.orElse(errorMessage);
System.out.println(result);
map 메서드는 함수형 프로그래밍 스타일로 코드를 깔끔하게 유지하는 데 도움을 줍니다.

Optional로 Course 클래스 재구성하기

Optional은 메서드의 반환값으로 주로 사용됩니다. 이를 통해 Null 관련 오류를 방지할 수 있습니다. 예를 들어, Course 클래스의 getStu 메서드를 다음과 같이 수정할 수 있습니다.

public Optional<Student> getStu(int i) {
    if (i >= stuList.size()) {
        return Optional.empty();
    }
    return Optional.ofNullable(stuList.get(i));
}
테스트 메서드도 간단히 구현할 수 있습니다.

private static void getStuByIndex(Course course, int index) {
    Student student = course.getStu(index).orElse(new Student("기본 학생"));
    System.out.println(student);
}

flatMap 활용

flatMap 메서드는 중첩된 Optional 객체를 다룰 때 매우 유용합니다.

Optional<Course> optionalCourse = Optional.ofNullable(course);
Optional<String> r0 = optionalCourse.flatMap(c -> c.getStu(0)).map(Student::getName);
Optional<String> r1 = optionalCourse.flatMap(c -> c.getStu(1)).map(Student::getName);
Optional<String> r2 = optionalCourse.flatMap(c -> c.getStu(2)).map(Student::getName);
Optional<String> r3 = optionalCourse.flatMap(c -> c.getStu(3)).map(Student::getName);

System.out.println(r0);
System.out.println(r1);
System.out.println(r2);
System.out.println(r3);
flatMap은 Optional> 형태를 Optional 형태로 변환하여 코드를 더 직관적으로 만듭니다.

태그: Java8 Optional NullHandling

7월 8일 21:27에 게시됨