먼저 들어가기에 앞서서 Dart 를 사용하면서 느낀점을 적어보려고 한다.
간단하게 먼저 결론을 내리자면 Enhanced Java 라고 생각하면 된다.
먼저 Dart 는 null safe 하다.
String name = null;
위와 같은 코드는 Java 에서는 컴파일 에러가 발생하지 않는다. 하지만 Dart 에서는 컴파일 에러가 발생한다.
String name = null;
Dart에서 null 을 허용하기 위해서는 '?' 를 붙혀줘야 하며 ?를 붙히지 않은 변수에는 초기 데이터 값을 넣어줘야 한다.
String name = null; // 컴파일 에러
String? name = null;
또한 Java 에서는 아래와 같은 코드가 가능하다.
String name = "hello";
name = null;
Dart 는 Java 보다 간결하다.
public class Person {
private String name;
private int age;
private String address;
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
}
위와 같은 코드는 Dart 에서는 아래와 같이 간결하게 표현할 수 있다.
class Person {
String name;
int age;
String address;
Person({this.name, this.age, this.address});
}
Dart 에서 생성자는 위와 같이 {} 로 묶어서 표현할 수 있다.
이는 dynamic 하게 생성자의 필요한 필드를 골라 사용 할 수 있다.
사용 되는 예시를 보면
Person(name: "hello", age: 10);
위 처럼 필드를 명시하고 넣어주면 필요한 필드만 사용하여 생성자를 호출 할 수 있다.
자바 처럼 필요한 생성자를 만들 때 마다 생성자를 만들어 주어야 하는 번거로움이 없다.
위 Dart의 생성자 필드를 보면 Flutter 에서 Widget 을 사용 할 때 생성자 필드를 사용하는 것과 유사하다. 맞다 그것이다.
Flutter 에서는 아래와 같이 Widget 을 생성 할 수 있다.
class MyWidget extends StatelessWidget {
final String name;
final int age;
MyWidget({this.name, this.age});
Widget build(BuildContext context) {
return Scaffold(
body: Text("Hello $name, $age"),
);
}
}
Scaffold 는 Flutter 에서 제공하는 Widget 이다. Widget이라는 단어가 조금 생소 할 수 있는데
결국 Class 이며 필드 명시를 통해 생성자를 불러와 필요한 필드만 사용 할 수 있다.
Dart 에서는 new 키워드를 사용하지 않는다. 근데 써도 문제 없다. 단지 new 키워드를 생략 할 수 있다는 점 정도만 알아두자.
Person person = Person(name: "hello", age: 10);
Dart 는 싱글 스레드로 동작한다.
또한 Dart 는 비동기 처리를 지원한다.
Future<String> fetchUserOrder() {
return Future.delayed(Duration(seconds: 2), () => "Large Latte");
}
Future<void> main() async {
print("Fetching user order...");
print(await fetchUserOrder());
}
위 코드는 2초 뒤에 Large Latte 를 출력하는 코드이다.
위 코드를 보면 Future 라는 것을 볼 수 있는데
Future 는 비동기 처리를 위한 클래스이다.
Future 를 사용하여 비동기 처리를 할 수 있다.
자바를 사용해봤으면 비동기 처리를 위해 Future 를 사용하는 것이 익숙할 것이다.
물론 자바는 비동기 처리를 위해 Future 뿐만 아니라 CompletableFuture, RxJava 등 다양한 라이브러리를 사용 해야 제대로 사용 할 수 있다.
Dart 는 자바와 달리 dynamic 이라는 타입이 있다.
dynamic 은 자바의 Object 와 같은 타입이다.
dynamic name = "hello";
name = 10;
위 코드는 dynamic 을 사용하여 name 변수에 String 타입의 hello 를 넣고 다시 int 타입의 10 을 넣는 코드이다.
자바에서는 Object 타입을 사용하여 위와 같은 코드를 작성 할 수 있다.
하지만 자바에서는 Object 타입을 사용하면 컴파일 타임에 타입을 체크 할 수 없다.
Dart 는 자바와 같은 컬렉션 API 를 지원한다. 내부 함수명도 거의 동일 하며 사용법도 거의 동일하다.
List<int> list = [1, 2, 3];
Set<int> set = {1, 2, 3};
Map<String, int> map = {"one": 1, "two": 2, "three": 3};
map.forEach((key, value) => print("$key: $value"));
List<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
Dart 는 자바와 같이 함수를 지원한다.
void main() {
print(sum(1, 2));
}
sum(int a, int b) {
return a + b;
}
여기서 return 타입의 타입추론이 가능하다. 따로 return 타입을 정의 하지 않아도 알아서 해준다.
위의 sum의 경우 int 타입을 리턴하기 때문에 return 타입을 int 로 추론한다.
Dart 는 자바와 비슷한 문법을 가지고 있어서 자바를 사용해본 사람이라면 쉽게 사용 할 수 있다.
where 절을 사용하여 필터링을 할 수 있고, map 을 사용하여 변환을 할 수 있다. 자바 stream 과 비슷하다.
또한 함수형 프로그래밍 언어 라서 함수를 변수에 할당 할 수 있다.
void main() {
var voidvoid = () => print("voidvoid");
}
자바 스크립트를 사용해본 사람이라면 쉽게 사용 할 수 있을 것이다.
자바에서 함수를 받을려면 함수 인터페이스를 사용해야 했는데 Dart 는 함수를 변수에 할당 할 수 있기 때문에 함수 인터페이스를 사용하지 않아도 된다.
여러모로 오랜만에 새로운 언어를 사용해보니 재밌었다.
먼저 자바와 큰 차이점이 없고 세부적으로만 다른 부분이라 차이점은 사용 할 때마다 익히면 되고
프로그래밍 적인 감각에서 객체지향적으로 사용 하면 되는 언어라 더 쉽게 사용 할 수 있을 것 같다.