DEV Community

Ge Ji
Ge Ji

Posted on

Dart Lesson 4: Collection Types (Part 2) — Maps and Enumerations

Today, we'll explore two more important data structures — Map and Enum — and dive into the characteristics and applications of immutable collections.

I. Map: A Collection of Key-Value Pairs

A Map is a collection of key-value pairs, similar to dictionaries or hash tables in other languages. It allows quick access values quickly through unique keys, making it ideal for storing associated data.

1. Creating a Map

Method 1: Using literals (Recommended)

void main() { // Create a Map with string keys and integer values Map<String, int> ages = {'Zhang San': 20, 'Li Si': 22, 'Wang Wu': 19}; // Create a Map with integer keys and string values Map<int, String> weekdays = {1: 'Monday', 2: 'Tuesday', 7: 'Sunday'}; print(ages); // Output: {Zhang San: 20, Li Si: 22, Wang Wu: 19} print(weekdays); // Output: {1: Monday, 2: Tuesday, 7: Sunday} } 
Enter fullscreen mode Exit fullscreen mode

Method 2: Using Map constructors

void main() { // Create empty Maps Map<String, String> emptyMap1 = {}; Map<String, String> emptyMap2 = Map<String, String>(); // Create a Map from entries Map<String, int> numberMap = Map.fromEntries([ MapEntry('one', 1), MapEntry('two', 2), ]); print(numberMap); // Output: {one: 1, two: 2} } 
Enter fullscreen mode Exit fullscreen mode

2. Key-Value Pair Operations

Map operations revolve around keys, including adding, accessing, modifying, and deleting:

void main() { Map<String, String> capitals = {'China': 'Beijing', 'USA': 'Washington'}; // Accessing values (through keys) print(capitals['China']); // Output: Beijing // Adding new key-value pairs capitals['Japan'] = 'Tokyo'; print(capitals); // Output: {China: Beijing, USA: Washington, Japan: Tokyo} // Modifying values (through keys) capitals['USA'] = 'Washington, D.C.'; print( capitals, ); // Output: {China: Beijing, USA: Washington, D.C., Japan: Tokyo} // Removing key-value pairs capitals.remove('Japan'); print(capitals); // Output: {China: Beijing, USA: Washington, D.C.} // Checking if a key exists print(capitals.containsKey('China')); // Output: true // Checking if a value exists print(capitals.containsValue('London')); // Output: false // Getting all keys/values print(capitals.keys); // Output: (China, USA) print(capitals.values); // Output: (Beijing, Washington, D.C.) // Getting length print(capitals.length); // Output: 2 // Clearing the Map capitals.clear(); print(capitals); // Output: {} } 
Enter fullscreen mode Exit fullscreen mode

3. Iterating Over Maps

There are several ways to traverse a Map, with the forEach method being most most commonly used:

void main() { Map<String, double> prices = {'Apple': 5.99, 'Banana': 3.99, 'Orange': 4.50}; // Method 1: Iterating with forEach (Recommended) prices.forEach((key, value) { print('The price of $key is \$$value'); }); // Output: // The price of Apple is $5.99 // The price of Banana is $3.99 // The price of Orange is $4.50 // Method 2: Iterating over keys and accessing values for (String fruit in prices.keys) { print('$fruit: \${prices[fruit]}'); } // Method 3: Iterating over entries (MapEntry) for (MapEntry<String, double> entry in prices.entries) { print('Key: ${entry.key}, Value: \${entry.value}'); } } 
Enter fullscreen mode Exit fullscreen mode

II. Enums: Named Constants for Fixed Collections

Enums are special types used to define fixed sets of named constants. They're perfect for representing scenarios with clearly defined options (like genders, states, types, etc.).

1. Defining Enums

Use the enum keyword to define enums:

// Define an enum for gender enum Gender { male, // Male female, // Female other, // Other } // Define an enum for order status enum OrderStatus { pending, // Pending payment paid, // Paid shipped, // Shipped delivered, // Delivered cancelled, // Cancelled } 
Enter fullscreen mode Exit fullscreen mode

2. Using Enums

Enum values can be accessed directly and provide type safety:

enum Gender { male, female, other } void main() { // Declare an enum variable Gender userGender = Gender.male; // Comparing enum values if (userGender == Gender.male) { print('User is male'); } // Using enums with switch-case (Recommended, as compiler checks for completeness) switch (userGender) { case Gender.male: print('Gender: Male'); break; case Gender.female: print('Gender: Female'); break; case Gender.other: print('Gender: Other'); break; } // Getting all enum values print(Gender.values); // Output: [Gender.male, Gender.female, Gender.other] // Getting the name of an enum value (as string) print(userGender.name); // Output: male // Getting an enum value by name Gender? gender = Gender.values.firstWhere( (g) => g.name == 'female', orElse: () => Gender.other, ); print(gender); // Output: Gender.female } 
Enter fullscreen mode Exit fullscreen mode

3. Use Cases for Enums

Enums are particularly suitable for:

  • Representing fixed sets of options (genders, colors, seasons)
  • State machines (order statuses, network states)
  • Replacing "magic numbers" (improving code readability)

Anti-pattern (Not recommended):

// Using numbers for statuses (magic numbers, poor readability) const int orderPending = 0; const int orderPaid = 1; 
Enter fullscreen mode Exit fullscreen mode

Best practice (Recommended):

// Using enums for statuses (clear and understandable) enum OrderStatus { pending, paid, shipped } 
Enter fullscreen mode Exit fullscreen mode

III. Immutable Collections (const/final) and Performance Impact

Collections are mutable by default (you can add/remove/modify elements), but in many scenarios we need immutable collections (cannot be modified after creation), which can be created using const or final.

1. Collections with final

A final collection has an immutable reference (cannot be reassigned), but its contents can be modified:

void main() { final List<int> numbers = [1, 2, 3]; // Can modify collection contents numbers.add(4); print(numbers); // Output: [1, 2, 3, 4] // Cannot reassign (compilation error) // numbers = [5, 6, 7]; } 
Enter fullscreen mode Exit fullscreen mode

2. Collections with const

A const collection is completely immutable (neither contents nor reference can be modified) and is created at compile time:

void main() { // Immutable List const List<int> immutableList = [1, 2, 3]; // Immutable Set const Set<String> immutableSet = {'a', 'b'}; // Immutable Map const Map<String, int> immutableMap = {'one': 1, 'two': 2}; // Attempting to modify will cause errors // immutableList.add(4); // Compilation error // immutableSet.remove('a'); // Compilation error // immutableMap['three'] = 3; // Compilation error } 
Enter fullscreen mode Exit fullscreen mode

3. Performance Impact of Immutable Collections

Memory optimization: Identical const collections share memory (singleton), reducing memory usage.

void main() { const list1 = [1, 2, 3]; const list2 = [1, 2, 3]; print(identical(list1, list2)); // Output: true (same memory address) } 
Enter fullscreen mode Exit fullscreen mode
  • Performance improvement: const collections are initialized at compile time, no need to recreate them at runtime, making them suitable for frequently used fixed data.
  • Thread safety: Immutable collections are inherently thread-safe, no need to worry about concurrent modification in multi-threaded environments.
  • Use cases: Configuration data, constant lists, fixed options, and other data that doesn't need modification.

IV. Collection Type Comparison and Selection Guide

Collection Type Core Characteristics Typical Use Cases
List Ordered, allows duplicates, index access Sequential data (list displays, array calculations)
Set Unordered, no duplicates, fast lookup Deduplication, set operations (intersection/union)
Map Key-value pairs, fast access by key Associated data (configuration tables, dictionaries, caches)
Enum Fixed constant collection, type-safe Status representation, option selection, replacing magic numbers

Selection recommendations:

  • Use List when you need to store data in order
  • Use Set when you need to ensure data uniqueness
  • Use Map when you need to look up values by key
  • Use Enum when you need to represent fixed options or states

Top comments (0)