개요

Dart 2.12 버전부터 도입된 Null Safety는 널 참조로 인한 런타임 에러를 방지하기 위한 기능입니다. 이를 통해 개발자는 컴파일 타임에 잠재적인 널 참조 오류를 발견하고 수정할 수 있습니다. 바로 들어가봅시다.
 
 

Non-nullable 타입

기본적으로 모든 타입은 null을 허용하지 않습니다.

String name = 'John';     // OK
int age = 25;            // OK
String name = null;      // Error
int age = null;         // Error

 

Nullable 타입

타입 뒤에 ?를 붙여 null을 허용할 수 있습니다.

String? nullableName = 'John';  // OK
nullableName = null;           // OK

int? nullableAge = 25;         // OK
nullableAge = null;           // OK

 
 

Null 검사 연산자

null 인식 연산자 (?)

객체가 null일 수 있는 경우 안전하게 접근하기 위해 사용합니다.

String? name = 'John';
print(name?.length);    // name이 null이 아니면 길이 출력, null이면 null 출력

String? nullName = null;
print(nullName?.length);  // null 출력

// 체이닝
class User {
  String? email;
}

User? user = User();
print(user?.email?.length);  // email이 null이면 null 출력

 
 

null 주장 연산자 (!)

nullable 타입을 non-nullable 타입으로 강제 변환합니다. null일 경우 런타임 에러가 발생하므로 주의해서 사용해야 합니다.

String? nullableName = 'John';
String nonNullableName = nullableName!;  // OK

String? nullName = null;
String nonNullName = nullName!;  // Runtime Error

 
 

null 병합 연산자 (??)

왼쪽 피연산자가 null인 경우 오른쪽 피연산자를 반환합니다.

String? name = null;
String displayName = name ?? 'Anonymous';  // 'Anonymous' 출력

String? firstName = null;
String? middleName = null;
String? lastName = 'Doe';
String displayName = firstName ?? middleName ?? lastName ?? 'Anonymous';  // 'Doe' 출력

 
 

late 키워드와 Null Safety

late 변수 선언

초기화를 나중에 하는 non-nullable 변수를 선언할 수 있습니다.

class User {
  late String email;  // 나중에 초기화할 non-nullable 변수
  
  void init(String userEmail) {
    email = userEmail;  // 초기화
  }
}

 
 

late final 변수

한 번만 초기화할 수 있는 변수를 선언합니다.

class User {
  late final String email;
  
  void init(String userEmail) {
    email = userEmail;  // 첫 번째 초기화 OK
    email = 'new@email.com';  // Error: final 변수는 재할당 불가
  }
}

 
 

주의사항

null 주장 연산자(!) 사용 시 주의사항

// 위험한 코드
void processUser(User? user) {
  print(user!.name);  // user가 null이면 런타임 에러
}

// 안전한 코드
void processUser(User? user) {
  if (user == null) return;
  print(user.name);  // null 체크 후 안전하게 접근
}

 
조건부 속성 접근

class User {
  final String? email;
  
  User({this.email});
  
  bool get hasEmail => email?.isNotEmpty == true;
  
  String get displayEmail => email ?? 'No email provided';
}

 
컬렉션에서의 Null Safety

// 리스트 요소가 null일 수 있는 경우
List<String?> nullableStrings = ['Hello', null, 'World'];

// 리스트 자체가 null일 수 있는 경우
List<String>? nullableList = null;

// 둘 다 null일 수 있는 경우
List<String?>? bothNullable = null;

// null이 아닌 요소만 처리
void processStrings(List<String?> strings) {
  for (final string in strings) {
    if (string != null) {
      print(string.toUpperCase());
    }
  }
}

 
 

결론

Null Safety는 코드의 안정성을 크게 향상시키는 중요한 기능입니다. 적절히 사용하면 널 참조 오류를 미리 방지하고, 코드의 의도를 더 명확하게 표현할 수 있습니다. 특히 Flutter 애플리케이션 개발에서는 필수적인 기능이므로, 잘 이해하고 활용하시기 바랍니다.

+ Recent posts