Classes, null safety, async, collections, mixins, generics, patterns & Flutter essentials
Languagevoid main() {
print('Hello, Dart!');
}
// Variables
var name = 'Alice'; // type inferred
String city = 'NYC'; // explicit type
final age = 30; // runtime constant
const pi = 3.14; // compile-time constant
late String description; // lazy initialization
// Types: int, double, String, bool, List, Map, Set, dynamic, num
int x = 42;
double y = 3.14;
num z = 42; // int or double
bool flag = true;
dynamic anything = 42; // any type (avoid when possible)
// Null safety (sound by default)
String? nullable; // can be null
String nonNull = 'hi'; // cannot be null
var len = nullable?.length ?? 0; // null-aware access + default
var val2 = nullable!; // assert non-null
nullable ??= 'default'; // assign if null
// String interpolation
var msg = 'Hello $name, age ${age + 1}';
var multi = '''
Multi-line string
''';
var raw = r'No \n escaping here';
// Type checks
if (obj is String) print(obj.length); // auto-promotes
if (obj is! int) print('not an int');
var str = obj as String; // explicit cast
// Typedef
typedef IntList = List<int>;
typedef Compare<T> = int Function(T a, T b);// if / else
if (score >= 90) {
print('A');
} else if (score >= 80) {
print('B');
} else {
print('C');
}
// Conditional expression
var label = score >= 90 ? 'A' : 'B';
// switch (classic)
switch (command) {
case 'start':
start();
break;
case 'stop':
case 'pause':
stop();
break;
default:
print('unknown');
}
// Switch expression (Dart 3+)
var result = switch (value) {
1 => 'one',
2 || 3 => 'two or three',
>= 4 && <= 10 => '4-10',
_ => 'other',
};
// for loops
for (var i = 0; i < 5; i++) print(i);
for (var item in list) print(item);
list.forEach((item) => print(item));
// while / do-while
while (x > 0) { x--; }
do { x++; } while (x < 10);
// Labeled loops
outer:
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
if (j == 3) break outer;
}
}
// assert (debug only)
assert(age >= 0, 'Age must be non-negative');// Basic function
int add(int a, int b) => a + b; // arrow syntax
String greet(String name) {
return 'Hello $name';
}
// Optional positional parameters
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) result = '$result via $device';
return result;
}
// Named parameters (can be required)
void createUser({required String name, int age = 0}) {}
createUser(name: 'Alice', age: 25);
// First-class functions
var multiply = (int a, int b) => a * b;
Function makeAdder(int n) => (int i) => n + i;
var add2 = makeAdder(2);
add2(3); // 5 — closure
// Higher-order functions
void execute(int Function(int, int) op) {
print(op(3, 4));
}
execute((a, b) => a + b);
// Tear-offs (function references)
list.forEach(print); // top-level function
list.map(element.toString); // instance method
list.where(int.parse != null); // static method
// Cascade notation (..)
var paint = Paint()
..color = Colors.red
..strokeWidth = 5.0
..style = PaintingStyle.stroke;// List
var list = <int>[1, 2, 3];
list.add(4); list.remove(2); list.length;
list.insert(0, 99); list.removeAt(0);
list.where((n) => n > 2).toList();
list.map((n) => n * 2).toList();
list.any((n) => n > 3);
list.every((n) => n > 0);
list.sort(); list.reversed.toList();
list.fold<int>(0, (sum, n) => sum + n);
list.reduce((a, b) => a + b);
list.firstWhere((n) => n > 2);
list.indexWhere((n) => n == 3);
list.take(2).toList(); list.skip(1).toList();
list.expand((n) => [n, n * 10]).toList();
// Spread, collection if/for
[...list, 5, 6] // spread operator
[for (var i in list) i * 2] // collection for
[if (flag) 99] // collection if
[...?nullableList] // null-aware spread
// Map
var map = <String, int>{'a': 1, 'b': 2};
map['c'] = 3;
map.containsKey('a'); map.containsValue(1);
map.forEach((k, v) => print('$k: $v'));
map.entries; map.keys; map.values;
map.update('a', (v) => v + 10);
map.removeWhere((k, v) => v > 2);
map.putIfAbsent('d', () => 4);
map.map((k, v) => MapEntry(k, v * 2));
// Set
var set = <int>{1, 2, 3};
set.add(4); set.contains(1);
set.union({3,4,5});
set.intersection({2,3});
set.difference({1});
// Unmodifiable collections
final immutable = List.unmodifiable([1,2,3]);
const constList = [1, 2, 3]; // deeply immutableclass Person {
final String name;
int _age; // private (underscore = library-level)
Person(this.name, this._age); // shorthand constructor
Person.guest() : name = 'Guest', _age = 0; // named constructor
int get age => _age; // getter
set age(int val) => _age = val; // setter
@override
String toString() => '$name ($_age)';
}
// Const constructor (compile-time objects)
class Point {
final double x, y;
const Point(this.x, this.y);
}
const origin = Point(0, 0);
// Factory constructor
class Logger {
static final _cache = <String, Logger>{};
factory Logger(String name) => _cache.putIfAbsent(name, () => Logger._internal(name));
Logger._internal(this.name);
final String name;
}
// Inheritance
class Student extends Person {
String school;
Student(super.name, super.age, this.school);
@override
String toString() => '${super.toString()} at $school';
}
// Abstract class + Interface
abstract class Shape {
double area(); // abstract method
void describe() => print('Shape with area ${area()}');
}
// Implements (every class is an implicit interface)
class MockPerson implements Person {
@override String get name => 'Mock';
// must implement ALL members
}
// Mixin
mixin Flyable {
void fly() => print('Flying!');
}
mixin Swimmable {
void swim() => print('Swimming!');
}
class Duck extends Animal with Flyable, Swimmable {}
// Mixin class (Dart 3+, can be both mixin and class)
mixin class Musician {
void play() => print('Playing!');
}
// Sealed class (Dart 3+ — exhaustive pattern matching)
sealed class Result {}
class Success extends Result { final String data; Success(this.data); }
class Failure extends Result { final String error; Failure(this.error); }
class Loading extends Result {}
// Enum with members
enum Status {
active('Active'), inactive('Inactive'), pending('Pending');
final String label;
const Status(this.label);
}
// Operator overloading
class Vector {
final double x, y;
const Vector(this.x, this.y);
Vector operator +(Vector other) => Vector(x + other.x, y + other.y);
bool operator ==(Object other) =>
other is Vector && x == other.x && y == other.y;
@override int get hashCode => Object.hash(x, y);
}// Generic class
class Box<T> {
final T value;
Box(this.value);
}
var box = Box<int>(42);
// Generic function
T first<T>(List<T> items) => items.first;
// Bounded generics
T max<T extends Comparable<T>>(T a, T b) => a.compareTo(b) >= 0 ? a : b;
// Covariant
class Animal {}
class Cat extends Animal {}
class Cage<T extends Animal> {
void put(covariant T animal) {}
}
// ── Patterns (Dart 3+) ──
// Destructuring patterns
var (a, b) = (1, 2); // record destructuring
var [x, y, ...rest] = [1, 2, 3, 4]; // list pattern
var {'name': name, 'age': age} = json; // map pattern
// Pattern matching in switch
String describe(Result r) => switch (r) {
Success(data: var d) => 'Got: $d',
Failure(error: var e) => 'Error: $e',
Loading() => 'Loading...',
};
// Guard clause
switch (value) {
case int n when n > 0:
print('positive: $n');
case int n:
print('non-positive: $n');
}
// if-case
if (json case {'name': String name, 'age': int age}) {
print('$name is $age');
}
// Records (Dart 3+)
(int, int) swap((int, int) pair) => (pair.$2, pair.$1);
({String name, int age}) person = (name: 'Alice', age: 30);
print(person.name);// Future (async/await)
Future<String> fetchData() async {
var response = await http.get(Uri.parse(url));
return response.body;
}
// Error handling
try {
var data = await fetchData();
} on SocketException {
print('No internet');
} catch (e, stackTrace) {
print('Error: $e');
print('Stack: $stackTrace');
}
// Multiple futures
var results = await Future.wait([fetch1(), fetch2()]);
var first = await Future.any([fetch1(), fetch2()]); // first to complete
// Future constructors
Future.delayed(Duration(seconds: 2), () => 'delayed');
Future.value(42); // already resolved
Future.error(Exception('oops')); // already rejected
// Future chaining
fetchUser()
.then((user) => fetchPosts(user.id))
.then((posts) => print(posts))
.catchError((e) => print('Error: $e'))
.whenComplete(() => print('Done'));
// Streams
Stream<int> countStream(int max) async* {
for (var i = 0; i < max; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
await for (var val in countStream(5)) {
print(val);
}
// Stream transformations
stream.map((n) => n * 2);
stream.where((n) => n > 5);
stream.expand((n) => [n, n * 10]);
stream.take(3);
stream.distinct();
stream.handleError((e) => print(e));
stream.listen(
(data) => print(data),
onError: (e) => print(e),
onDone: () => print('done'),
cancelOnError: false,
);
// StreamController (custom streams)
final controller = StreamController<int>.broadcast();
controller.sink.add(1);
controller.stream.listen((val) => print(val));
controller.close();
// Isolates (true parallelism)
var result = await Isolate.run(() => heavyComputation());
// or use compute() in Flutter// try / on / catch / finally
try {
riskyOperation();
} on FormatException catch (e) {
print('Format error: $e');
} on IOException {
print('I/O error'); // catch without binding
} catch (e, stackTrace) {
print('Unknown: $e');
print(stackTrace);
} finally {
cleanup();
}
// Throw
throw FormatException('Invalid input');
throw 'Something went wrong'; // can throw any object
// Custom exception
class ApiException implements Exception {
final String message;
final int statusCode;
ApiException(this.message, this.statusCode);
@override
String toString() => 'ApiException($statusCode): $message';
}
// Rethrow
try {
riskyOperation();
} catch (e) {
log(e);
rethrow; // preserves original stack trace
}
// Result pattern (functional style)
sealed class Result<T> {}
class Ok<T> extends Result<T> { final T value; Ok(this.value); }
class Err<T> extends Result<T> { final String error; Err(this.error); }
Result<User> getUser(int id) {
try {
return Ok(fetchUser(id));
} catch (e) {
return Err(e.toString());
}
}// Extension methods
extension StringUtils on String {
String get reversed => split('').reversed.join();
bool get isEmail => RegExp(r'^[\w.-]+@[\w.-]+\.\w+$').hasMatch(this);
String truncate(int len) => length > len ? '${substring(0, len)}...' : this;
}
'hello'.reversed; // 'olleh'
'a@b.com'.isEmail; // true
// Extension types (Dart 3.3+, zero-cost wrappers)
extension type UserId(int id) {
bool get isValid => id > 0;
}
var uid = UserId(42);
uid.isValid; // true
// RegExp
var re = RegExp(r'\d+');
re.hasMatch('abc123'); // true
re.firstMatch('abc123')?.group(0); // '123'
'abc123def456'.replaceAll(re, '#'); // 'abc#def#'
// DateTime
var now = DateTime.now();
var date = DateTime(2026, 4, 1);
var parsed = DateTime.parse('2026-04-01');
now.difference(date).inDays;
now.add(Duration(hours: 3));
now.isBefore(date); now.isAfter(date);
// JSON encoding/decoding
import 'dart:convert';
var jsonStr = jsonEncode({'name': 'Alice', 'age': 30});
var map = jsonDecode(jsonStr) as Map<String, dynamic>;
// File I/O
import 'dart:io';
var content = await File('data.txt').readAsString();
await File('output.txt').writeAsString('Hello');
var lines = await File('data.txt').readAsLines();// ── Stateless Widget ──
class Greeting extends StatelessWidget {
final String name;
const Greeting({super.key, required this.name});
@override
Widget build(BuildContext context) {
return Text('Hello $name');
}
}
// ── Stateful Widget ──
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => _count++),
child: Text('Count: $_count'),
);
}
}
// ── Common Layouts ──
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 8),
Row(children: [Icon(Icons.home), Text('Home')]),
Expanded(child: ListView.builder(
itemCount: items.length,
itemBuilder: (ctx, i) => ListTile(title: Text(items[i])),
)),
],
)
// ── Navigation ──
Navigator.push(context, MaterialPageRoute(builder: (_) => DetailPage()));
Navigator.pop(context);
Navigator.pushNamed(context, '/detail', arguments: {'id': 42});
// GoRouter (declarative)
final router = GoRouter(routes: [
GoRoute(path: '/', builder: (_, __) => HomePage()),
GoRoute(path: '/detail/:id', builder: (_, state) =>
DetailPage(id: state.pathParameters['id']!)),
]);
// ── State Management (Riverpod) ──
final counterProvider = StateProvider<int>((_) => 0);
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('$count'),
);
}
}
// AsyncNotifierProvider (Riverpod)
final usersProvider = AsyncNotifierProvider<UsersNotifier, List<User>>(
UsersNotifier.new);
class UsersNotifier extends AsyncNotifier<List<User>> {
@override
Future<List<User>> build() async => await api.fetchUsers();
}
// ── HTTP & Dio ──
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
final response = await dio.get('/users');
final users = (response.data as List).map((j) => User.fromJson(j)).toList();
// ── JSON Serialization (freezed + json_serializable) ──
@freezed
class User with _$User {
const factory User({
required int id,
required String name,
@Default('') String email,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
// ── Flutter CLI ──
// flutter create my_app
// flutter run -d chrome
// flutter build apk --release
// flutter build ios --release
// flutter pub add provider
// flutter pub run build_runner build
// dart run build_runner watch --delete-conflicting-outputs