Java/강의

[📙 Java 문법 종합반] 3-2. Optional - null 을 다루는 법

가지코딩 2025. 4. 16. 17:08

📙 목차

  1. Optional 이란?
  2. Optional 활용하기
  3. 실습 과제

🧡 학습 목표

  • Optional 을 사용하는 이유와 개념을 학습한다.

1. Optional 이란?

  • null 을 안전하게 다루게 해주는 객체
  • null 을 직접 다루는 대신 Optional 을 사용하면 NullPointerException 을 방지할 수 있다.
    • NPE(NullPointerException) 예외는 런타임 예외이고 컴파일러가 잡아주지 못 한다.
💡 null 이란?
프로그래밍에서 값이 없음 또는 참조하지 않음 을 나타내는 키워드

 

 

예시 - Optional이 필요한 상황

public class Student {
    private String name;

    public String getName() {
        return this.name;
    }
}

-----

public class Camp {
    private Student student;
    
    // ⚠️ null 을 반환할 수 있는 메서드
    public Student getStudent() {
        return student;
    }
}

-----

public class Main {
    public static void main(String[] args) {
        Camp camp = new Camp();
        Student student = camp.getStudent(); // ⚠️ student 에는 null 이 담김

        String studentName = student.getName(); // 🔥 NPE 발생 -> 프로그램 종료
        System.out.println("studentName = " + studentName);
    }
}

 

 

* NULL 을 직접 처리의 한계

  • if 문을 활용해서 null 처리를 할 수 있지만, 모든 코드에서 null 이 발생할 가능성을 미리 예측하고 처리하는 것은 현실적으로 어렵다.
public class Main {
    public static void main(String[] args) {
        Camp camp = new Camp();
        Student student = camp.getStudent();

        String studentName;
        if (student != null) { // ⚠️ 가능은하지만 현실적으로 어려움
            studentName = student.getName();
        } else {
            studentName = "등록된 학생 없음"; // 기본값 제공
        }

        System.out.println("studentName = " + studentName);
    }
}

2. Optional 활용하기

<참고 자료>

 

Optional (Java Platform SE 8 )

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl

docs.oracle.com

  • Optional 객체는 값이 있을 수도 있고 없을 수도 있는 컨테이너라고 생각한다.
  • Optional 객체를 메서드 반환 자료형에 선언해서 해당 메서드가 null 이 반환될 가능성을 명확하게 전달할 수 있다.
  • Optional.ofNullable() 을 사용하여  null 이 반환될 수 있는 객체를 감싼다.
  • 활용할 때는 isPresent() 와 같은 Optional API 를 통해 안전하게 null 처리를 할 수 있다.

 

 

isPresent()

  • Optional 내부의 값이 존재할 경우에 true 반환
  • 내부 값이 null 일 경우 false 를 반환
import java.util.Optional;

public class Camp {
    private Student student;

    // ✅ null 이 반환될 수 있음을 명확하게 표시
    public Optional<Student> getStudent() {
        return Optional.ofNullable(student);
    }
}

-----

public class Main {
    public static void main(String[] args) {
        Camp camp = new Camp();

        //  Optional 객체 반환받음
        Optional<Student> studentOptional = camp.getStudent();

        // Optional 객체의 기능 활용
        boolean flag = studentOptional.isPresent();
        if (flag) {
            Student student = studentOptional.get(); // ✅ 안전하게 Student 객체 가져오기
            String studentName = student.getName();
            System.out.println("studentName = " + studentName);

        } else {
            System.out.println("학생이 없습니다.");
        }
    }
}

 

 

orElseGet()

  • orElseGet()은 값이 없을 때만 기본값을 제공하는 로직을 실행하는 메서드이다.
  • 값이 있을때는 기존 값을 그대로 get 한다.
  • orElseGet()을 제대로 활용하려면 람다 표현식을 이해해야 한다.
import java.util.Optional;

public class Camp {
    private Student student;

    // ✅ null 이 반환될 수 있음을 명확하게 표시
    public Optional<Student> getStudent() {
        return Optional.ofNullable(student);
    }
}

-----

public class Main {
    public static void main(String[] args) {
        Camp camp = new Camp();

        // ✅ Optional 객체의 기능 활용 (orElseGet 사용)
        Student student = camp.getStudent()
                              .orElseGet(() -> new Student("미등록 학생"));

        System.out.println("studentName = " + student.getName());
    }
}

3. 실습 과제

수강생의 이름을 입력받고 해당 이름이 캠프에 등록되어 있는지 확인하는 프로그램을 만드세요.

  • Student , CampService , Main 클래스를 활용하세요.
  • 캠프에는 3 명의 학생이 존재합니다. Spartan, Steve, John
  • Optional.ofNullable() 로 Optional 객체를 만드세요
  • isPresent() 로 Optional 에 값이 있는지 확인하세요.
  • get() 으로 안전하게 데이터를 꺼내오세요.
public class Student {
    private String name;
    private String exp;

    public Student(String name, String exp) {
        this.name = name;
        this.exp = exp;
    }

    public String getName(){
        return name;
    }

    public void introduce(){
        System.out.printf("안녕하세요. %s %s 입니다.\n", exp, this.name);
    }
}
import java.util.Optional;

public class CampService {
    static Student[] students = {
            new Student("Spartan", "재학생"),
            new Student("Steve", "재학생"),
            new Student("John", "재학생")
    };

    public Optional<Student> searchStudent(String name) {
        for (Student s : students) {
            if (name.equals(s.getName())) {
                return Optional.of(s);
            }
        }

        return Optional.empty();
    }
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        System.out.print("이름을 입력하시오: ");
        String name = in.next();

        CampService cs = new CampService();
        cs.searchStudent(name).orElseGet(() -> {
            System.out.println("등록되지 않은 학생, 등록 절차 진행 ...");
            return new Student(name, "신입생");
        }).introduce();
    }
}

 


orElse

위 Main 클래스 코드의, orElseGet 과 동일하게 동작한다. (콘솔 출력 제외)

  • 하지만, 이 코드는 Optional에 값이 있어도 불필요하게 객체를 생성하는 단점이 있다.
  • 값이 자주 비어있고, 기본값 생성이 가벼운 경우 orElse 를 활용한다.
  • 값이 자주 있고, 기본값 생성이 무겁거나 복잡한 경우 orElseGet 을 활용한다.

* orElseGet 내부 람다식은 Optional에 값이 없을 때만 실행된다.

cs.searchStudent(name).orElse(new Student(name, "신입생")).introduce();

 

Optional.of(value), Optional.ofNullable(value), Optional.empty() 차이

  • Optional.of(value): 값이 확실히 있을 때 활용
  • Optional.ofNullable(value): 값이 null일 수도 있을 때 활용, null일 경우 빈 Optional 이 된다.
  • Optional.empty: 빈 Optional 을 만들고 싶을 때 활용