o7planning

Dart methods Tutorial and Examples

  1. What is method?
  2. Regular method
  3. Static method
  4. Abstract method
  5. Optional Parameters
  6. Optional Named Parameters
  7. Override a method
  8. Final method?

1. What is method?

In the Dart programming language, a method is a block of code that is defined inside a class and runs only when called. Methods divide a large task into small parts and perform a specific program operation. This process increases code reusability and enhances the program's modular approach.
Basically, methods are divided into 3 types:
  • Regular method (non-static and non-abstract).
  • Static method.
  • Abstract method.

2. Regular method

The syntax for defining a regular method:
return_type method_name(arguments)    {  
     // statement(s)  
}
  • return_type: The return data type of the method. Use the void keyword as a return type if the method returns nothing.
  • method_name: The method name. Unlike other languages like Java, Dart does not allow two methods with the same name, even if they have different parameters. This is required to be able to convert Dart code to JavaScript.
  • arguments: The method's parameters.
Example: Cat class and its sayHello(..) method. To call sayHello(..) you must create a Cat object and call the method using dot notation.
method_ex1.dart
class Cat {
  void sayHello(String name) {
    print("Hello $name");
  }
}
void main() {
  Cat tom = new Cat(); // Create a Cat object.  
  tom.sayHello("Jerry"); // Call the method through the object.
}
Output:
Hello Jerry
A method can contain 0, 1, or more parameters, separated by commas.
method_ex2.dart
class Rectangle {
  int width;
  int height;
  Rectangle(this.width, this.height); // Constructor

  int getArea() {
    return width * height;
  }
  void changeWidthHeight(int newWidth, int newHeight)  {
      width = newWidth;
      height = newHeight;
  }
  void showMe()  {
     print('I am a rectangle, width: $width, height: $height');
  }
}
void main() {
   Rectangle rec = Rectangle(5, 10); // Create an object.
   
   rec.showMe();  // Call the method.
   var area = rec.getArea();  // Call the method.
   print('Area: $area');
   print(' --- Change width and height --- ');
   rec.changeWidthHeight(25, 15); // Set newWidth, newHeight
   rec.showMe(); // Call the method.  
   area = rec.getArea(); // Call the method.
   print('Area: $area');
}
Output:
I am a rectangle, width: 5, height: 10
Area: 50
--- Change width and height ---
I am a rectangle, width: 25, height: 15
Area: 375

3. Static method

Dart uses the static keyword and regular method definition syntax to define a static method.
The syntax for defining static method:
static return_type method_name(arguments)    {  
     // statement(s)  
}
Characteristics of static method:
  • Static method is called via the class name and dot notation. For example MyUtility.sum(100, 50). The class name and dot notation can be omitted if you call the static method internally.
  • Non-static members of a class cannot appear in a static method unless they are accessed through the object (See the example below).
method_static_ex1.dart
class MyUtility {
  static int sum(int a, int b)  {
    return a + b;
  }
  static int minus(int a, int b)  {
    return a - b;
  }
}
void main() {
   var result = MyUtility.sum(100, 50);
   print('Sum Result: $result');
   result = MyUtility.minus(100, 50);
   print('Minus Result: $result');
}
Output:
Sum Result: 150
Minus Result: 50
Next, look at the example below:
  • side1, side2 and side3 are non-static fields of the Triangle class, which cannot appear in static method.
  • Calling a static method within the class that defined it may not need the class name and dot notation.
method_static_ex2.dart
class Triangle {
  late double side1;
  late double side2;
  late double side3;
  static const String DEFAULT_COLOR  = 'blue'; // Static field

  Triangle(double s1, double s2, double s3) {
    bool valid = isValidSides(s1, s2, s3); // Check if all sides are valid.
    if(!valid) {
      throw ArgumentError('Invalid Sides!'); // Throw an Error.
    }
     side1 = s1;
     side2 = s2;
     side3 = s3;
  }
  static bool isValidSides(double s1, double s2, double s3)  {
     if(s1 < 0 || s2 < 0 || s3 < 0)  {
       return false;
     }
     return s1 + s2 > s3 && s1 + s3 > s2 && s2 + s3 > s1;
  }
  bool isEquilateralTriangle() {
      return side1 == side2 && side2 == side3;
  }
}
void main() {
   bool valid = Triangle.isValidSides(6, 8, 10);
   print('Are sides 6, 8 and 10 valid to make a triangle? $valid');
   var triangle = Triangle(3.0, 4.0, 5.0);
   // Check if the triangle is equilateral triangle.
   var check = triangle.isEquilateralTriangle();
   print('Is Equilateral Triangle? $check');
}
Output:
Are sides 6, 8 and 10 valid to make a triangle? true
Is Equilateral Triangle? false

4. Abstract method

In Dart language, abstract method is a non-static method and has no body.
abstract return_type method_name(arguments);
A class with at least one abstract method must be declared abstract. One of its subclasses will override abstract methods and write content for them.
Example: The Person class below must be declared as an abstract class because it has at least one abstract method.
method_abstract_ex1.dart
abstract class Person {
  void sayHello(); // An abstract method.
}
class EnglishPerson extends Person {
  void sayHello() {
    print("Hello");
  }
}
class RussianPerson extends Person {
   void sayHello() {
      print("Привет");
   }
}
void main() {
    Person enPerson = EnglishPerson();
    enPerson.sayHello();
    Person ruPerson = RussianPerson();
    ruPerson.sayHello();
}
Output:
Hello
Привет
  • Dart Classes

5. Optional Parameters

As mentioned above, classes in Dart and JavaScript do not support methods with the same name, but a method can include optional parameters.
Syntax:
// Non-static method with optional arguments:
return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]){   
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,[typeP? argP, typeQ? argQ]);
Or syntax - Optional parameters with default values:
// Non-static method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]){   
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                        [typeP? argP = defaultValueP, typeQ? argQ]);
Example:
method_optional_args_ex1.dart
class MyUtility {
  static String concat(String s1, String s2, [String? s3]) {
    if (s3 != null) {
      return s1 + s2 + s3;
    }
    return s1 + s2;
  }
  static double sum(double v1, double v2, [double? v3, double? v4]) {
    return v1 + v2 + (v3 ?? 0) + (v4 ?? 0);
  }
}
void main() {
  String result1 = MyUtility.concat('One', 'Two');
  print('result1: $result1');
  String result2 = MyUtility.concat('One', 'Two', 'Three');
  print('result2: $result2');
  double value1 = MyUtility.sum(1, 2, 3, 4);
  print('value1: $value1');
  double value2 = MyUtility.sum(1, 2, 3);
  print('value2: $value2');
  double value3 = MyUtility.sum(1, 2);
  print('value3: $value3');
}
Output:
result1: OneTwo
result2: OneTwoThree
value1: 10.0
value2: 6.0
value3: 3.0
Example:
method_optional_args_ex2.dart
class Team {
   List<String> members = [];

   void addMembers(String member1, [String? member2, String? member3]) {
      members.add(member1);
      if(member2!= null) {
         members.add(member2);
      }
      if(member3!= null) {
         members.add(member3);
      }
   }
   void printAllMembers()  {
      print(' --- All members: --- ');
      for(var member in members) {
          print(member);
      }
   }
}  
void main() {
  var team = Team(); // Create Team object.
  team.addMembers('Tom', 'Jerry');
  team.printAllMembers();
}
Output:
--- All members: ---
Tom
Jerry

6. Optional Named Parameters

Optional Named Parameters are parameters enclosed in braces { } and are the last parameters in the list of parameters. All these parameters have default values.
Syntax:
// Non-static method with optional named parameters:
return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ}){  
     // statement(s)  
}
// Static method with optional arguments:
static return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ}){  
     // statement(s)  
}
// Abstract method with optional arguments:
return_type method_name(typeM argM, typeN argN,
                  {typeP paramP = defaultValueP, typeQ paramQ = defaultValueQ});
Example:
method_optional_named_args_ex1.dart
class StringUtility {
  static String concatAndTrim(String s1, String s2, {bool trimLeft = true, bool trimRight = true}) {
    var s = s1 + s2;
    if (trimLeft && trimRight) {
      return s.trim();
    } else if (trimLeft) {
      return s.trimLeft();
    } else if (trimRight) {
      return s.trimRight();
    }
    return s;
  }
}
void main() {
  var s1 = '  One  ';
  var s2 = '  Two  ';
  var result1 = StringUtility.concatAndTrim(s1, s2); // trim left and right
  print('result1: -->$result1<-- (Trim left and right)');

  var result2 = StringUtility.concatAndTrim(s1, s2, trimLeft: false); // trim right only
  print('result2: -->$result2<-- (Trim right only)');

  var result3 = StringUtility.concatAndTrim(s1, s2, trimRight: false); // trim left only
  print('result3: -->$result3<-- (Trim left only)' );

  var result4 = StringUtility.concatAndTrim(s1, s2, trimLeft: false, trimRight: false); // no trim
  print('result4: -->$result4<!-- (No Trim)');
}
Output:
result1: -->One    Two<-- (Trim left and right)
result2: -->  One    Two<-- (Trim right only)
result3: -->One    Two  <-- (Trim left only)
result4: -->  One    Two  <!-- (No Trim)

7. Override a method

A subclass can override a method of the parent class if the following conditions are met:
  • The two methods must have the same name and the same parameters.
  • The return type of the two methods must be the same or the return type of the method in the subclass must be a subtype of the return type of the method in the parent class.
Example:
  • The Cat class overrides the sayAnything() method of the Animal class.
  • @override is an optional annotation placed in front of the overridden method (in the subclass). If you accidentally rename this method in the parent class, the Dart compiler will give you an error.
method_override_ex1.dart
class Animal {
  void sayAnything() {
    print('<Nothing>');
  }
}
class Cat extends Animal {
  @override
  void sayAnything() { // Override method from parent class.
    print('Meow');
  }
}
void main() {
  Animal animal = Cat();
  animal.sayAnything();
}
Output:
Meow
Example: Use the super keyword to call a method of the parent class.
method_override_ex2.dart
class BoldFormatter {
  String formatText(String text) {
    return '<b>' + text + '</b>';
  }
}
class BoldItalicFormatter extends BoldFormatter {
  @override
  String formatText(String text) { // Override method from parent class.
    var boldText = super.formatText(text); // Call super method.
    return '<i>' + boldText + '</i>';
  }
}
void main() {
  var formatter = BoldItalicFormatter();
  var formattedText = formatter.formatText('Hello');
  print(formattedText);
}
Output:
<i><b>Hello</b></i>

8. Final method?

In the Java language, you can use the final keyword for a method to ensure that subclasses cannot override this method. Is there something similar in Dart?
package:meta gives you @nonVirtual to prevent a subclass from overriding a method of the parent class. It helps Analyzer to report an error if you violate that, but no other action is taken.
method_final_ex1.dart
import 'package:meta/meta.dart';

class Foo {
   @nonVirtual
   void bar() {
     print("bar from Foo!");
   }
}
class SubFoo extends Foo {
  @override
   void bar()  {
      print("bar from SubFoo");
   }
}
Basically, you will get a warning from Analyzer that looks like this:
The member 'bar' is declared non-virtual in 'Foo'
and can't be overridden in subclasses.dart(invalid_override_of_non_virtual_member)
  • Thêm thư viện vào dự án Dart