기초
Null Safety
값이 없을 수 있는 상황을 타입으로 표현하고 안전하게 다룹니다.
핵심 개념
Null Safety 주요 항목
기본 개념
Dart에서 String은 null이 될 수 없고, String?은 null이 될 수 있습니다.
언제 쓰나: nullable 값을 사용할 때는 검사하거나 기본값을 제공해야 합니다.
Flutter에서: Flutter 앱에서는 API 응답, 선택된 항목, 아직 로드되지 않은 데이터에서 nullable 값을 자주 만납니다.
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('기본 개념', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Dart에서 String은 null이 될 수 없고, String?은 null이 될 수 있습니다.'),
],
),
),
)
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'기본 개념',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
)
],
),
)
기본 개념
안전한 처리
?? 연산자는 값이 null일 때 대체값을 제공합니다.
언제 쓰나: ?. 연산자는 왼쪽 값이 null이면 접근을 중단합니다.
Flutter에서: ! 연산자는 null이 아님을 강제로 주장하므로 마지막 수단으로만 씁니다.
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('안전한 처리', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('?? 연산자는 값이 null일 때 대체값을 제공합니다.'),
],
),
),
)
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'안전한 처리',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
)
],
),
)
안전한 처리
상세 설명
더 알아보기
Null safety의 핵심은 null 가능성을 코드의 타입에 드러내는 것입니다. 이 덕분에 런타임에 갑자기 null 오류가 터지기 전에 컴파일 단계에서 위험을 발견할 수 있습니다.
다만 ! 연산자를 습관적으로 사용하면 null safety의 장점을 스스로 무너뜨리게 됩니다. null 검사를 하거나 기본값을 제공하는 방식으로 흐름을 명확히 만드는 편이 좋습니다.
코드
예제
// 사용자의 선택 입력을 담는 모델입니다.
class UserProfile {
const UserProfile({required this.name, this.nickname, this.age});
// name은 필수값이므로 null이 될 수 없는 String입니다.
final String name;
// nickname은 사용자가 입력하지 않을 수 있으므로 String?입니다.
final String? nickname;
// age도 선택 입력이므로 int?입니다.
final int? age;
// 닉네임이 비어 있지 않으면 닉네임을, 없으면 이름을 표시합니다.
String get displayName => nickname?.trim().isNotEmpty == true
? nickname!
: name;
// age가 null이면 기본 문구를 보여 줍니다.
String get ageLabel => age == null ? '나이 미입력' : '$age세';
}
void printProfile(UserProfile profile) {
// getter를 사용하면 화면 코드에서 null 처리 로직이 단순해집니다.
print(profile.displayName);
print(profile.ageLabel);
}
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'실행 출력',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('> profile.displayName
> profile.ageLabel')
],
)
],
),
)
실행 출력
> profile.displayName
> profile.ageLabel
주의 사항
실무에서 확인할 점
- nullable 값에 바로 접근하지 말고 null 검사, ?., ?? 중 하나를 선택하세요.
- late는 편리하지만 초기화 시점을 보장할 수 있을 때만 쓰세요.
- required는 null safety와 함께 생성자의 의도를 명확하게 만듭니다.
다음 단계
실습 체크리스트
String과 String? 구분??와 ?. 사용! 남용 피하기
- 출처세부 기준과 최신 변경 사항을 확인할 수 있습니다.
- Flutter API Reference클래스, 메서드, 생성자 세부 정의를 확인합니다.
- Dart languageDart 문법 자체가 궁금할 때 함께 봅니다.