제어문은 프로그램의 실행 흐름을 제어하는 구문입니다. 보통 프로그래밍 언어에서 제공하는 if~else, for, while, do~while, break, continue, switch~case 등이 제어문이며, 다트를 비롯해 대부분 언어에서 비슷하게 동작합니다. 이 절에서는 프로그램의 실행 흐름에서 다른 언어와 차이 나는 부분만 살펴보겠습니다.
for 반복문에서 in 연산자
for 문은 어떤 구문을 반복해서 실행할 때 이용하며 반복해서 실행할 조건을 다음처럼 초기화; 조건; 증감 형태로 작성합니다.
// for 문 사용 예
main() {
var list = [10, 20, 30];
for(var i = 0; i < list.length; i++) {
print(list[i]);
}
}
▶ 실행 결과
10
20
30
그런데 이런 형태를 in 연산자를 사용해 간소화할 수 있습니다. for 문에 범위 연산자인 in을 사용하면 오른쪽에 명시한 컬렉션 타입의 데이터 개수만큼 반복해서 실행합니다. 다음 코드에서 in 연산자는 for 문이 한 번 실행될 때마다 list의 데이터를 순서대로 가져와 x 변수에 대입합니다.
// in 연산자로 간소화한 반복문
main() {
var list = [10, 20, 30];
for(var x in list) {
print(x);
}
}
switch~case 선택문
switch~case 구문은 if~else 구문과 더불어 조건에 따라 실행 흐름을 분기할 때 많이 사용합니다. 다트에서는 switch의 조건을 정수나 문자열 타입으로 지정할 수 있습니다. 또한 case가 여러 개라면 맨 마지막 case 문을 제외하고는 break, continue, return, throw 중 하나를 작성해 그다음 실행 흐름을 결정해 줘야 합니다.
- break: switch 문 나가기
- continue: 특정 위치(라벨)로 이동하기
- return: switch 문이 작성된 함수 종료하기(반환하기)
- throw: switch 문이 작성된 함수 종료하기(던지기)
예를 들어 다음 코드는 첫 번째 case 문에서 오류가 발생합니다.
switch~case 문 잘못 사용 예
some(arg) {
switch(arg) {
case 'A': // 오류
print('A');
case 'B':
print('B');
}
}
case 문을 2개 선언했는데 첫 번째 case 문에 break, continue, return, throw 등으로 그다음 실행 흐름을 지정하지 않아서 오류가 발생합니다. 따라서 다음처럼 작성해야 바르게 동작합니다.
// switch~case 문 올바른 사용 예
some(arg) {
switch(arg) {
case 'A';
print('A');
break;
case 'B';
print('B');
}
}
예외 던지기와 예외 처리
예외 처리문은 대부분 언어에서 제공하는 런 타임 오류를 제어하는 구문이며 다트에서도 다른 언어와 비슷하게 예외 처리문을 제공합니다.
예외를 던지는 throw 문
프로그램이 실행되다 특정 시점에 예외를 발생시키고 싶다면 throw 문을 이용합니다. throw 오른쪽에는 객체를 작성하는데 다음 코드에서는 다트에서 예외를 표현하는 Exception 클래스를 작성했습니다.
// 예외 던지기
some() {
throw Exception('my exception');
}
Exception 클래스 이외에 다른 객체를 던져도 됩니다. 다음처럼 문자열을 던질 수도 있습니다. throw 문이 실행되면 예외가 발생해 some() 함수를 호출한 곳에 해당 문자열을 던집니다.
// 문자열 던지기
some() {
throw 'my exception';
}
Exception 클래스 이외에 다른 객체를 던져도 됩니다. 다음처럼 문자열을 던질 수도 있습니다. throw 문이 실행되면 예외가 발생해 some() 함수를 호출한 곳에 해당 문자열을 던집니다.
// 문자열 던지기
some() {
throw 'my exception';
}
물론 다음처럼 개발자가 만든 객체를 던져도 됩니다.
// 사용자 정의 객체 던지기
class User{}
some() {
throw User();
}
try~on~finally 예외 처리
try~on~finally 구문은 예외 처리 조합입니다. try문에 작성한 코드에서 예외가 발생하면 on 문이 실행되며, finally 문에는 예외아 상관없이 무조건 실행할 코드를 작성합니다. 다음 코드는 try~on~finally 구문으로 예외를 처리하는 예이며 some() 함수를 호출할 때 예외가 발생합니다.
// try~on~finally 예외 처리
some() {
throw FormatException('my exception');
}
main(List<String> args) {
try {
print('step1....');
some();
print('step2....');
} on FormatException {
print('step3....');
} on Exception {
print('step4....');
} finally {
print('step5....');
}
print('step6....');
}
▶실행 결과
step1....
step3....
step5....
step6....
try 문에서 호출한 some() 함수에서 throw 문으로 예외를 던집니다. 따라서 some() 호출문 아래에 있는 구문은 실행되지 않고 실행 흐름은 on 문으로 넘어갑니다. on 문은 여러 개 정의할 수 있으며 on 오른쪽에는 처리할 예외의 종류, 즉 타입을 작성합니다. 그러면 예외가 발생할때 해당 예외 타입에 맞는 on 문을 찾아서 실행합니다. 예제에서는 some() 함수에서 Format Exception 예외를 던지므로 on FormatException { } 구문이 실행됩니다.
만약 예외 처리문에서 어떤 예외가 발생했는지 알고자 한다면 catch 문으로 예외 객체를 받을 수 있습니다. on FormatException catch(e)라고 작성하면 발생한 예외 객체가 e에 전달됩니다.
// 예외 객체 가져오기
some() {
throw FormatException('my exception');
}
main(List<String> args) {
try {
print('step1....');
some();
print('step2....');
} on FormatException catch(e) {
print('step3....$e');
} on Exception catch(e) {
print('step4....$e');
} finally {
print('step5....');
}
print('step6....');
}
▶실행 결과
step1....
step3....FormatException: my exception
step5....
step6....
만약 예외 종류를 구분하지 않겠다면 다음처럼 간단하게 작성할 수도 있습니다.
// try~catch 예외 처리
try {
some();
} catch(e) {
print('catch....$e');
}
'Flutter' 카테고리의 다른 글
생성자와 멤버 초기화 (0) | 2024.11.13 |
---|---|
클래스와 객체 (0) | 2024.11.13 |
기타 연산자 알아보기 (0) | 2024.11.12 |
게터와 세터 함수 (0) | 2024.11.12 |
함수 타입 인수 (0) | 2024.11.12 |