Lesson 1 · 1 of 20
Classes and initializer lists · Dart
Define Dart classes with final fields, this-shorthand constructors and initializer lists that prepare the data before the constructor body runs.

A class bundles data and behaviour. Product has three `final` fields: they are set once, when the object is built, and never change, which is the usual style in Dart for objects that represent data. The price is stored in cents (priceCents), an integer, so no rounding errors creep in.
The constructor Product(this.name, this.priceCents, {this.stock = 0}) uses initializing formal parameters: this.name copies the argument straight into the field, with no assignment to write. stock is a named parameter with a default value, which is why cable shows 0 in stock. The label getter builds its text from the fields.
Invoice needs a bit more: it stores a cleaned-up customer name and works out the total. Since those fields are final, they cannot be assigned inside the constructor body; that is what the initializer list is for, the part after the colon. customer = customer.trim().toUpperCase() sets the field from the parameter of the same name, and totalCents adds up the line prices with fold.
The initializers run in order and before the body in braces. By the time the body runs, the object is complete: that is why it can print this.customer, the field already in capitals (GARCIA LTD), rather than customer, which inside the constructor is the parameter, still padded with spaces. Notice that number uses the short this.number form and happily coexists with the initializer list.
Code · main.dart
// A product in a shop catalogue.class Product { final String name; final int priceCents; final int stock; // this.name copies the argument straight into the field. Product(this.name, this.priceCents, {this.stock = 0}); String get label => '$name - ${(priceCents / 100).toStringAsFixed(2)} EUR';}class Invoice { final String number; final String customer; final int totalCents; // The initializer list (after the colon) sets final fields // before the constructor body runs. Invoice(this.number, String customer, List<Product> lines) : customer = customer.trim().toUpperCase(), totalCents = lines.fold(0, (sum, p) => sum + p.priceCents) { print('Invoice $number ready for ${this.customer}'); }}void main() { final mouse = Product('Wireless mouse', 1999, stock: 25); final cable = Product('USB-C cable', 899); print(mouse.label); print('${cable.name}: ${cable.stock} in stock'); final invoice = Invoice('INV-0042', ' Garcia Ltd ', [mouse, cable]); print('Total: ${invoice.totalCents} cents');}Output · dart run main.dart
Wireless mouse - 19.99 EUR USB-C cable: 0 in stock Invoice INV-0042 ready for GARCIA LTD Total: 2898 cents
Key points
finalfields are set exactly once, when the object is built.this.fieldin the parameter list copies the argument into the field.- The initializer list (
: field = ...) runs before the body. - Inside the constructor,
this.xis the field andxis the parameter. - Store money as whole cents to avoid rounding errors.
Exercise
Add a final int lineCount field to Invoice, computed in the initializer list with lines.length, and print it next to the total.