Back-End (Web)/JAVA

[JAVA] NULL

JABHACK 2024. 11. 13. 10:17

NULL

📌참조 변수가 아무 객체도 가리키지 않음을 나타내는 특수한 값입니다.

  • 특징:
    • 객체가 생성되지 않았거나, 특정 객체를 참조하지 않는 상태를 나타냅니다.
    • 참조 타입(객체 타입)에만 사용할 수 있습니다. (예: String, Integer, 사용자 정의 클래스 등)
    • 원시 타입(예: int, float)에는 사용할 수 없습니다.
    • null 값의 변수로 메서드를 호출하려고 하면 **NullPointerException**이 발생합니다.

빈 공간 (Empty String)

  • 의미: 길이가 0인 문자열로, 내용이 없는 문자열을 의미합니다.
  • 표현: 빈 문자열은 "" (따옴표만 있는 문자열)로 표현됩니다.
  • 특징:
    • 문자열 객체가 존재하지만, 내용이 없습니다.
    • 메모리에는 문자열 객체가 생성되며, 이는 null과 다릅니다.
    • isEmpty() 메서드로 확인할 수 있습니다.

 

 

 

 

  • NULL은 사용에 있어 주의가 필요한데 null이 반환되면 보통 nullPointerException이 발생하게 된다.
public class NullIsDanger {
    public static void main(String[] args) {

        SomeDBClient myDB = new SomeDBClient();
        
        String userId = myDB.findUserIdByUsername("HelloWorldMan");

        System.out.println("HelloWorldMan's user Id is : " + userId);
    }
}

class SomeDBClient {

    public String findUserIdByUsername(String username) {
        // ... db에서 찾아오는 로직
				String data = "DB Connection Result";

        if (data != null) {
            return data;
        } else {
            return null;
        } 
    }
    
}
  1. 논리적으로도, 환경적으로도 null이 반환될 여지가 있음에도, null이 반환될 수 있음을 명시하지 않았습니다.
  2. 메인 함수 쪽에서, 사용할 때 null 체크를 하지 않아, 만약 null이 반환 된다면, nullPointerException이 발생하게 됩니다.

 

  • 위 문제를 해결하는 방법은 크게 3가지인데
  • 1. null이 반환될 여지를 명시하고, 그 메서드를 사용하는 사람이 조심하기
  • 2. 결과값을 감싼 객체를 반환 = 결과값 + 성공 여부를 함께 반환 = 성공 못해도 값을 null로 반환하진 않는다.
  • 3. java.util.Optiona 객체 사용

+ 감싼 객체 : 보통 반환은 1개의 데이터만 반환하지만 객체의 형태로 반환하면 여러 데이터를 담아 반환이 가능하다.

 

 

java.util.Optional

📌 Java 8에서 도입된 클래스입니다. 널(null) 값을 명시적으로 처리하기 위해 사용됩니다. Optional은 값이 있을 수도 있고 없을 수도 있다는 개념을 명확하게 표현하고, 널 포인터 예외(NullPointerException)를 방지하는 데 도움을 줍니다.

 

Optional 기본 정리

  • Java8에서는 Optional<T> 클래스를 사용해 Null Pointer Exception을 방지할 수 있도록 도와줍니다.
  • Optional<T>는 null이 올 수 있는 값을 감싸는 Wrapper 클래스입니다.
  • Optional이 비어있더라도, 참조해도 Null Pointer Exception가 발생하지 않습니다.
  • Optional은 객체를 생성하는데 오버헤드가 있을 수 있기 때문에 성능이 중요한 경우 과도한 사용을 피하는 것이 좋습니다.
  • 모든 메서드에서 Optional을 사용해야 할 필요는 없으며, 주로 널 처리가 필요한 곳에서만 사용하는 것이 바람직합니다.

 

Optional 사용법

1. Optional 생성

  • Optional.of(): 값이 반드시 존재할 때 사용합니다. 만약 null을 넣으려 하면 NullPointerException이 발생합니다.
  • Optional.ofNullable(): 값이 null일 수도 있는 경우에 사용합니다.
  • Optional.empty(): 빈 Optional 객체를 생성합니다. (값이 없음을 나타냄)
Optional<String> presentValue = Optional.of("Hello");
Optional<String> nullableValue = Optional.ofNullable(null); // null이 될 수 있음
Optional<String> emptyValue = Optional.empty(); // 빈 Optional

 

2. 값 존재 여부 확인

  • isPresent(): 값이 존재하면 true, 그렇지 않으면 false를 반환합니다.
  • ifPresent(): 값이 존재하면 해당 값을 처리하는 람다를 실행합니다.
Optional<String> value = Optional.of("Hello");

// 값이 존재하는지 확인
if (value.isPresent()) {
    System.out.println(value.get()); // 값이 존재하면 출력
}

// 값이 존재하면 처리하는 방식
value.ifPresent(v -> System.out.println("Value: " + v));

 

3. 값을 안전하게 얻기

  • get(): Optional에 값이 존재하면 해당 값을 반환합니다. 값이 없으면 NoSuchElementException을 발생시킵니다.
  • orElse(): 값이 존재하면 해당 값을 반환하고, 없으면 기본값을 반환합니다.
  • orElseGet(): 값이 존재하면 해당 값을 반환하고, 없으면 제공된 Supplier로 기본값을 생성하여 반환합니다.
  • orElseThrow(): 값이 없으면 예외를 던집니다.
Optional<String> value = Optional.ofNullable("Hello");

// 값이 없으면 예외를 던짐
String result = value.orElseThrow(() -> new IllegalArgumentException("Value is missing"));

// 값이 없으면 기본값을 반환
String result2 = value.orElse("Default Value");

// 값이 없으면 Supplier로 기본값을 생성
String result3 = value.orElseGet(() -> "Generated Value");

 

4. 값 변환

  • map(): Optional에 값이 있을 때, 해당 값에 연산을 적용하여 새로운 Optional을 반환합니다.
  • flatMap(): map()과 유사하지만, 결과가 또 다른 Optional일 때 사용됩니다. (중첩된 Optional을 평평하게 만들어줍니다.)
Optional<String> value = Optional.of("Hello");

// 값이 있을 때 대문자로 변환
Optional<String> upperCaseValue = value.map(String::toUpperCase);
System.out.println(upperCaseValue.get()); // HELLO

// flatMap 예시
Optional<String> result = value.flatMap(v -> Optional.of(v + " World"));
System.out.println(result.get()); // Hello World

 

5. 필터링

  • filter(): Optional에 값이 있을 때, 특정 조건을 만족하는 값만 남기고 필터링합니다.
Optional<String> value = Optional.of("Hello");

// 값이 "Hello"인 경우에만 값 반환
Optional<String> filteredValue = value.filter(v -> v.equals("Hello"));
filteredValue.ifPresent(System.out::println); // Hello

 

< 예시 >

public class OptionalExample {
    public static void main(String[] args) {
        Optional<String> name = Optional.ofNullable(getName());

        // 값이 있으면 출력
        name.ifPresent(System.out::println);

        // 값이 없으면 기본값 반환
        String defaultName = name.orElse("Default Name");
        System.out.println("Name: " + defaultName);

        // 값이 없으면 예외 던지기
        String forcedName = name.orElseThrow(() -> new RuntimeException("Name is missing"));
    }

    public static String getName() {
        // 값이 없으면 null을 반환
        return null;
    }
}

'Back-End (Web) > JAVA' 카테고리의 다른 글

[JAVA] 자바의 정렬  (0) 2024.11.21
[JAVA] 응용 정리  (1) 2024.11.15
[JAVA] 쓰레드 & 람다 함수 & 스트림  (3) 2024.11.13
[JAVA] Generic  (3) 2024.11.12
[JAVA] 오류 및 예외에 대한 이해  (1) 2024.11.12