DART 总结(对比JAVA)

本文介绍了Dart编程语言的关键概念和特性,包括它的强类型、对象模型、内置库、变量、基本数据类型、函数、异常处理、类、泛型以及异步处理。Dart与Java的主要区别在于它没有public、private等访问修饰符,而是通过下划线开头的变量和函数表示私有。此外,Dart支持AOT和JIT编译,拥有流畅的动画性能和声明式布局,以及独特的mixin和未来(Future)及流(Stream)处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DART概述

概念

Dart 是由谷歌开发的通用的编程语言,它常用于构建web、服务器、桌面和移动应用程序。
Dart是一种简洁、清晰、基于类的面向对象的语言,它是基于JavaScript的但是结构要比JavaScript要多。
Dart是一种面向对象的、类定义的、垃圾回收语言。它支持接口、mixin、类对象,具有化泛型、静态类型等。

  • 在dart中,能够放在变量中的所有内容都是对象,每个对象都是一个类的实例。甚至于数字、函数和null值都是对象,并且所有对象都继承自Object类;
  • Dart是强类型语言,但类型标识是可选的,因为Dart可以推断类型,所以可以直接用数据类型定义变量,但是也可以用var声明变量进行类型推断;
  • 能够放在变量中的所有内容都是对象,所以如果一个变量没有初始化值,那它的默认值就为null;
  • 在dart中,即使是函数也是对象,并且具有类型Function类型;
  • 与Java不同,Dart没有关键字public、protected和private。如想设置私有变量或函数,则变量和函数名以下划线(_)开头;
  • dart中,没有函数重载;

特性

1.Dart是AOT(Ahead Of Time)编译的,可编译成快速,可预测的本地代码。
2.Dart可以JIT(Just In Time)编译,开发周期快,为Flutter热重载提供基础。
3.Dart可以轻松创建60fps运行的流畅动画和转场。
4.Dart的声明式编程布局,易于阅读和可视化,不需要单独的声明式布局语言,如:XML,JSX。
5.Dart非常易于学习,具有静态和动态语言,编程人员都熟悉的特性。

Dart的内置库

包名描述
dart:asynv异步编程,提供Future,Stream类
dart:collection集合
dart:convert不同类型的字符编码解码
dart:coreDart语言核心功能,内置类型
dart:html网页开发用到的库
dart:io文件读写,IO相关
dart:math数字常量以及函数,随机算法等
dart:svg事件和动画矢量图支持

变量

命名

在Dart语言当中,定义变量的方式是

dataType viriableName = Initial Valute

这里其实和Java是一样的,不仅如此连命名的方式也和Java相同,都是采用驼峰命名的方式。

声明

在声明的时候,除了基本数据类型之外,还有三种变量的声明: vardynamicObject

var:如果没有初始值的时候,var可以变成任意类型。

dynamic:动态任意类型,编译阶段不检查类型。

Object: 动态任意类型,在编译阶段检查类型。

和var的区别:
var如果有初始值,那么类型会被锁定。

void main(){
  // a 的数据类型可以随意改变,这种类型就是 dynamic
  var a ;
  a = 10;
  a = "dart";

  // 这里我们使用 dynamic 声明
  dynamic d = 10;
  d = 'dart';
}

默认值

1.没有初始值的变量会自动获取一个默认值null。
2.一切皆为对象,对象的默认值是null。

私有变量

  • 与Java不同,Dart没有关键字public、protected和private。如想设置私有变量或函数,则变量和函数名以下划线(_)开头

final和const

表示不可改变

const 变量是一个编译时常量,final变量在第一次使用时被初始化

相同点:

  • 声明的类型可以省略
  • 初始化后不能再赋值
  • 不能和var同时使用

不同点:

  • 类级别常量,使用static const
  • const可使用其他const 常量的值来初始化其值
  • 使用const赋值声明,const可以省略
  • 可以更改非final、非const变量的值。即使曾经具有const值
  • const导致的不可变性是可以传递的
  • 相同的const常量不会再内存中重复创建
  • const需要是编译时常量

基本数据类型

8种基本数据类型:

Number

数值型里面有包含了int型和doubule两种类型,这两种和Java类似,其中int是整数型,double是64-bit双精度浮点数,这两种都是Number类型的子类。

void main() {
  num a = 10; // 整形
  a = 20.1; // 浮点型
  print(a);// 20.1

  int i = 10;
  // i = 10.1;     // 这个地方会报错,因为将 int 型的数据改为 double 型 向下转型
  // i = int.parse('10.1'); // 字符串转换为int类型
  i = 10.1.round();// 通过round()方法将double转换为int
  print(i); // 10

  double d = 20.1;
  d = 20; // 这个地方不会报错,因为将 double 型的数据改为 int 型,向上转型
  // 向上转型 : (小范围)---》(大范围),这种属于自动转换
  // 向下转型 : (大范围)---》(小范围),这种属于强制转换
  print(d); // 20.0
}

数值型的操作

运算符: +、 - 、* 、/ 、 ~/ 、 %

常用属性: isNaN、isEven、isOdd

常用方法:abs()、round()、floorl()、ceil()、toInt()、toDouble()

String

Dart字符串是UTF-16编码的字符序列。

1.可以使用单引号或者双引号来创建字符

void main() {
  print("This is a String");
  print('This is also a stirng');
}

这两个是一样的。

单双引号成对嵌套

void main() {
  String str = '单引号中的"双引号"';
  String str1 = "双引号中的'单引号'";
  print(str); // 单引号中的"双引号"
  print(str1); //双引号中的'单引号'

  String str2 = '单引号中的 \'单引号\' ';
  String str3 = "双引号中的 \"双引号\" ";
  print(str2); //单引号中的 '单引号'
  print(str3); //双引号中的 "双引号"
}

2.字符串拼接

void main() {
  String s1 = "First string.....";
  String s2 = "   Second string";
  print(s1 + s2); // First string.....   Second string
  
  // 使用空格即可拼接字符串
  
  // 使用的是空格拼接,多个空格也可以
  String str1 = '单引号空格字符串' '拼接' '~'; // 单引号字符串空格拼接~
  
  // 使用换行符以及空格
  String str2 = '单引号符串'
      '换行了'
      '再加空格'
      '拼接'; // 单引号符串换行了再加空格拼接

  // 单双引号 空格拼接
  String str3 = "单双引号空格字符串" '拼接' "~"; // 单双引号字符串空格拼接~

  // 单双引号 换行符以及空格
  String str4 = "单双引号符串"
      '换行了'
      '再加空格'
      '拼接'; // 单双引号符串换行了再加空格拼接
  
  // 下面这两种情况会报错
  // String blockStr4 = '单引号''''空格';
  // String blockStr5 = "双引号""""空格";
}

3.字符插值

${exprsssion},如果表达式是一个标识符,可以省略{},如果表达式的结果为一个对象,Dart会调用对象的toString()函数来获取一个字符串。

void main() {
  String s1 = "First string.";
  print("String 后面拼接 $s1");// String 后面拼接 First string.

  print("The sum of 1 and 1 equals ${1 + 1}.");// // The sum of 1 and 1 equals 2.
}

4.多行显示
使用双引号创建多行字符
还可以使用(’)和(")

 var s = 'Firtst'
  'Second'
  "Third";
   print(s);// FirtstSecondThird

使用三引表示多行字符

 var multilineString = """This is a
   multiline string
   consistiong of
   multiple lines""";
  print(multilineString);
/*  This is a
   multiline string
   consistiong of
   multiple lines */

5.使用r前缀创建“原始raw”字符串

  String s4 ="adbchi\ndfafa";
  print(s4);// 转译 /n

  String s5 =r"adbchi\ndfafa";
  print(s5);// 不转译 /n

  //输出的结果
  adbchi
  dfafa
  adbchi\ndfafa

Bool

Dart的bool和Java类似只有两种类型,一种是true一种是false,但是,不同的是bool对象未初始化的默认值是null

List

  • 实例化数组

      // 使用构造创建
      var list = new List();
    
      //创建一个int类型的list
      List intlist = [1, 2, 3];
    
      // 创建一个常量List, 不可以改变的List
      List constList = const[10, 7, 23];
    
  • Dart就可以直接打印list包含list的元素,java中直接打印list结果是地址值。

     var list = [0, 1, 2, 3, 4, 5, 6];
     print(list); // [0, 1, 2, 3, 4, 5, 6]
    
  • Dart中List的下标索引和java一样都是从0开始。

  • Dart中List也支持泛型,这点和java一样,同时还可以进行泛型的判断。

     var list1 = List<String>();
     print(list1 is List<String>); // true 这里的 is 是一种类型判断
    
  • 有增删改查的操作,支持倒叙,自带顺序,洗牌,可以使用+将两个List合并。

      var list = [0, 1, 2, 3, 4, 5, 6];
      print(list);
      var list2 = [7, 8, 9, 10, 11];
      print(list + list2); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    
  • 数组中的常用操作

      //  在数组中可以存放多个不同类型的对象
      var list = [1, 2, 3, 'Flutter', true];
      print(list);      // 输出的结果:[1, 2, 3, Flutter, true]
    
      // 修改数组下标为2 的值
      list[2] = 'Dart'; // 输出的结果:[1, 2, Dart, Flutter, true]
    
    	// 从下标0开始,下标2结束(不包括2),修改之间的值为字符a
      list.fillRange(0, 2, 'a'); // 输出的结果:[a, a, Dart, Flutter, true]
    
      // 获取数组的长度
      print(list.length);   // 输出的结果:5
    
      // 向数组中添加元素
      list.add("value"); // [a, a, Dart, Flutter, true, value]    
    	var addList=['8','9'];
      list.addAll(addList);//[a, a, Dart, Flutter, true, value,8,9]
    
      // 向数组中的指定位置添加元素
      list.insert(1, 'element');  // [a, element, a, Dart, Flutter, true, value]
    	// 向数组中指定位置加入一组元素
    	list.insertAll(3, ['1','2','3','4']);// [a, element, a, 1, 2, 3, 4, Dart, Flutter, true, value]
    
      // 移除数组中的元素
      list.remove("value");//[a, element, a, 1, 2, 3, 4, Dart, Flutter, true]
      // 移除数组中指定的元素
      list.removeAt(1);// [a, a, 1, 2, 3, 4, Dart, Flutter, true]
    
      // 判断数组中是否有某个元素
      print(list.indexOf("element"));   // 输出结果:-1
    
      // 可以使用 sort() 函数来排序, 但是由于我们使用定义的数组类型不一样,就不能使用
      var intlist = [1, 2, 5, 6 ,3];
      // 根据语法提示: List.sort([(int, int) → int compare]) → void
      intlist.sort( (a, b) =>  a.compareTo(b) );// [1, 2, 3, 5, 6]
    
    
    	//数组翻转
      var newList1=list.reversed.toList();// [true, Flutter, Dart, 4, 3, 2, 1, a, a]
      var bools=list.isEmpty;//判断集合是否为空
      var bools2=list.isNotEmpty;//判断集合是否不为空
     
      var str=list.join('***');//集合转字符串 可以用任意字符拼接
    	// a***a***1***2***3***4***Dart***Flutter***true
      var newList2=str.split('***');//字符串转集合
    	// [a, a, 1, 2, 3, 4, Dart, Flutter, true]
    
  • 遍历

     var list = [1, 2, 3, 'Flutter', true]; 
    //两种遍历方式
      list.forEach((element) {
        print(element);
      });
     
      for (var item in list) {
        print(item);
      }
    

Set

Dart里面的Set和Java类似,也是不能存放重复的元素。
set 是有序的

  • 两种初始化方式

    var setName = <dataType>{}
    Set<dataType> setName ={}
    
  • 和 JAVA 语言的区别:
    difference:返回set1集合里面有但是set2里面没有的元素集合

     Set<String> set1 = {"1","2","3","4","5"};
     Set<String> set2 = {"1","2","3"};
     print(set1.difference(set2)); // {4, 5}
    

    intersection:返回set1和set2的交集

Set set1 = {“1”,“2”,“3”,“4”,“5”};
Set set2 = {“1”,“2”,“3”};
print(set1.intersection(set2)); // {1, 2, 3}


**union**:返回set1和set2的并集

```dart
Set<String> set1 = {"1","2","3","4","5"};
  Set<String> set2 = {"1","2","3","6"};
print(set1.union(set2)); // {1, 2, 3, 4, 5, 6}

retainAll:set1只保留某些元素(要保留的元素要在原set中存在)

Map

和Java类似

创建 Map 集合

void main(){

  // 创建Map 
  var language = {'fisrt': 'dart', 'second': 'java'};

  // 创建不可变的 Map
  var constLanguage = const {'fisrt': 'dart', 'second': 'java'};

  // 通过构造器创建
  var initLanguage = new Map();
}

Map 中常用的方法

void main(){

  // 创建Map 
  var map = {'fisrt': 'dart', 'second': 'java'};

  // 获取长度
  print(map.length);    // 输出结果:2

  // 判断是否为空
  print(map.isEmpty);     // 输出结果:false
  print(map.isNotEmpty);  // 输出结果:true

  // 获取到所有的 key
  print(map.keys);        // 输出结果:(fisrt, second)

  // 获取到所有的 values
  print(map.values);      // 输出结果:(dart, java)

  // 判断是否包含某个key
  print(map.containsKey("key"));    // 输出结果:false

  // 判断是否包含某个value
  print(map.containsValue("key"));    // 输出结果:false

  // 添加一个新的元素进去
  map['third'] = 'key';
  print(map);         // 输出结果:{fisrt: dart, second: java, third: key}

  // 循环打印 代码提示:Map.forEach((String, String) → void f) → void
  map.forEach( (key, value) =>  getMap(key, value) );
}

void getMap(key, value){
  print("key:${key}, value:${value}");
}
void main() {
  var list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

  //如果所有的数据都满足条件的就返回true,否则返回false
  var f = list2.every((value) {
    return value > 0;
  });
  print(f); // true

  //如果所有的数据至少有一项满足条件就返回true,否则返回false
  var f2 = list2.any((value) {
    return value > 10;
  });
  print(f2); // false

  //循环遍历,输出满足条件的数据
  var newList5 = list2.where((value) {
    return value > 5;
  });
  print(newList5.toList()); //[6, 7, 8, 9, 10]

  //集合进阶
  List list3 = [
    {
      'province': '河北',
      'city': ['石家庄', '廊坊', '辛集'],
    },
    {
      'province': '北京',
      'city': ['朝阳区', '海淀区', '昌平区'],
    },
    {
      'province': '山东',
      'city': ['青岛', '淄博', '济南'],
    }
  ];

  for (int i = 0; i < list3.length; i++) {
    print(list3[i]);
  }
/*   {province: 河北, city: [石家庄, 廊坊, 辛集]}
  {province: 北京, city: [朝阳区, 海淀区, 昌平区]}
  {province: 山东, city: [青岛, 淄博, 济南]} */
  for (int i = 0; i < list3.length; i++) {
    print(list3[i]['province'] + " ");

    for (int j = 0; j < list3[i]['city'].length; j++) {
      print("   " + list3[i]['city'][j]);
    }
  }
  /* 
河北 
   石家庄
   廊坊
   辛集
北京 
   朝阳区
   海淀区
   昌平区
山东 
   青岛
   淄博
   济南
    */
}

Map遍历

  map.forEach((key, value) {
    print("map----"+key+' : '+value);
   });
 
 
  //forin循环输出数据
  for(var item in mapList2){
    print("----"+item);
  }

Runes

Runes在Dart当中是字符的UTF-32的编码

Main(){
  Runes runes = new Runes('\u{1f605} \u6211‘);
  var str1 = String.fromCharCodes(runes);  
  print(str1); // 😅 我
}

Symbol

Symbol标识符,主要是反射的作用,现在在mirrors模块已经被移除了。

类型转换

  • int / double

    类似于 java 的类型转换

    向上转型 : (小范围)—》(大范围),这种属于自动转换
    向下转型 : (大范围)—》(小范围),这种属于强制转换

    	int i = 10;
      // i = 10.1;     // 这个地方会报错,因为将 int 型的数据改为 double 型 向下转型
      // i = int.parse('10.1'); // 字符串转换为int类型
      i = 10.1.round();// 通过round()方法将double转换为int
      print(i); // 10
    
      double d = 20.1;
      d = 20; // 这个地方不会报错,因为将 double 型的数据改为 int 型,向上转型
      print(d); // 20.0
    
  • int / string

      int j = 10;
      String jstr = j.toString();
      int z = int.parse('66');
      // int z = int.parse('66.66'); // 报错,类型不匹配
      print(jstr); // 10
      print(z); // 66
    
  • double / string

      double f = double.parse('9.9');
      double ff = double.parse('9');
      String fstr = 3.1415926.toStringAsFixed(6); // 保留6位小数
      String ffstr = 3.1415926.toString();
      print(f); // 9.9
      print(ff); // 9.0
      print(fstr); //3.141593
      print(ffstr); // 3.1415926
    

assert

assert 是语言内置的断言函数,仅在检查模式下有效
在开发过程中, 除非条件为真,否则会引发异常。(断言失败则程序立刻终止)。

// 检查是否为空
var fullName = '';
assert(fullName.isEmpty);

// 为0检查
var hitPoints = 0;
assert(hitPoints <= 0);

// 检查是否为 null.
var unicorn;
assert(unicorn == null);

// 检查是否为 NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

函数

定义

总体来说,和java类似。

void main() {
  firstMethod();
  secondMethod();
  thirdMethod();
}
 
void firstMethod(){
  print('定义了一个方法');
}
 
String getPrint(){
  return '带有返回值的方法';
}
 
int thirdMethod(int x,int y){
  return x+y;//必填带参函数
}

其他几个特殊点:

  • 可在函数内定义

  • 定义函数时可以省略类型

  • 支持缩写语法=>

    int add(int a, int b) => a + b;
    

可选参数

用大括号进行声明可选参数,可选参数没有顺序,可以设置默认值,不传就是默认值

  • 可以选择命名参数

  • 可以选择位置参数

  • 可以添加默认参数

    printer(num n, {String s1, String s2}) {
      print(n); // 75
      print(s1); // hello
      print(s2); // null
    }
    main() { printer(75, s1: 'hello'); }
    
    printer(num n, {String s1, String s2}) {
    print(n); // 75
      print(s1); // null
      print(s2); // null
    }
    main() { printer(75); }
    
    printer(num n, {String s1, String s2}) {
      print(n); // 75
      print(s1); // hello
      print(s2); // there
    

}
main() { printer(75, s1: ‘hello’, s2: ‘there’); }


```dart
printer(num n, {String s1 = '这是默认S1', String s2})) {
  print(n); // 75
  print(s1); // 这是默认S1
  print(s2); // null
}
main() { printer(75); }
String mysteryMessage(String who, [String what, String where]){
  var message = '$who';
  if(what != null && where == null){
    message = '$message said $what';
  } else if (where != null){
    message = '$message said $what at $where';
  }
  return message;
}

main() {
  var result = mysteryMessage('Billy', 'howdy', 'the ranch');
  print(result); // Billy said howdy at the ranch
}

匿名函数

可以赋值给变量,通过变量调用
可以在其他函数当中直接调用或者传递给其他函数

  //赋值给变量
  //无参匿名函数
  var anonFunc1 = () => print('无参匿名函数');
  anonFunc1(); // 输出结果: 无参匿名函数

  //有参匿名函数
  var anonFunc = (name) => 'I am $name';
  print(anonFunc('damon')); // 输出结果:  I am damon

  //通过()调用,不推荐
  //  (()=>print('不推荐'))();

  //匿名函数传参
  List test(List list, String func(str)) {
    for (var i = 0; i < list.length; i++) {
      list[i] = func(list[i]);
    }
    return list;
  }

  var list = ['d', 'a', 'm', 'o', 'n'];
  //String * int, Dart和Python可以这样用
  print(test(list, (str) => str * 2)); //[dd, aa, mm, oo, nn] 

  //List.forEach()就用的匿名函数
  List list1 = [11, 12, 13];
  list1.forEach((item) => print('$item'));

  //返回Function对象(闭包)
  Function makeAddFunc(int x) {
    x++;
    return (int y) => x + y; // 返回的是 function 对象
  }

  var addFunc = makeAddFunc(2);
  print(addFunc(3)); // 6
void main() {
  // 函数别名
  MyFunc myFunc;
  //可以指向任何同签名的函数
  myFunc = subtsract;
  myFunc(4, 2); // subtsract: 2
  myFunc = divide;
  myFunc(4, 2); // divide: 2.0
  //typedef 作为参数传递给函数
  calculator(4, 2, subtsract); // subtsract: 2
}

// 函数的类型是Function类型,typedef就是给Function取个别名,相当于进行一次简单的封装
typedef MyFunc(int a, int b);
//根据MyFunc相同的函数签名定义两个函数
subtsract(int a, int b) {
  print('subtsract: ${a - b}');
}

divide(int a, int b) {
  print('divide: ${a / b}');
}

//typedef 也可以作为参数传递给函数
calculator(int a, int b, MyFunc func) {
  func(a, b);
}

逻辑运算

操作符

操作符大部分和Java相同。标红的是不同的

逻辑运算

?.
条件成员访问 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员。

String a;
print(a?.length); // null

String a="aaa";
print(a?.length); // 3

~/
取商操作符
被除数 ÷ 除数 = 商 … 余数,A ~/ B = C,这个C就是商。相当于Java里的 /

  int a = 5;
  print(a ~/ 2); // 2.5
  print(a / 2); // 2

as、is、is!
类型判定操作
类型判定操作符:as、is、is!在运行时判定对象类型

void main() {
  //as 类型转换
  num iNum = 1;
  num dNum = 1.0;
  int i = iNum as int;
  double d = dNum as double;
  print([i, d]); // [1, 1.0]

//  String s = iNum as String;

  //is 如果对象是指定的类型返回 True
  print(iNum is int); // false
  Child child;
  Child child1 = new Child();
  print(child is Parent); // false //child is Null 
  print(child1 is Parent); // false

  //is! 如果对象是指定的类型返回 False
  print(iNum is! int); // false
}
class Child {}
class Parent {}


级联操作符
连续调用多个函数以及访问成员变量。
两个点的级联语法不是一个操作符。 只是一个 Dart 特殊语法。

 StringBuffer sb = new StringBuffer();
  sb
    ..write('dongnao')
    ..write('flutter')
    ..write('\n')
    ..writeln('damon');
print(sb); //输出结果:
dongnaoflutter
damon

流程控制语句

if else
for,forEach,for-in
while,do-while
break,continue
switch case
assert

大部分使用方法都是和Java相同的。不同的有
for-in

  var colorList = ['black','red','yellow'];
  for(var i in colorList){
    print(i);
  }
  输出:
  I/flutter (31601): black
  I/flutter (31601): red
  I/flutter (31601): yellow

assert
断言,它可以为代码执行设置条件,用于bool条件为false时中断正常的运行。

assert(condition,optional,message)

  var variable;
  print(variable);
  assert(variable!=null);
  variable = 6;
  print(variable);
  输出:
   [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter_app/main.dart': Failed assertion: line 50 pos 10: 'variable!=null': is not true.

异常

不管是Java语言还是Dart语言,都有异常,以及异常的捕获,但是不同的是dart中的异常都是非检查异常,方法可以不声明可能抛出的异常,也不要求捕获任何异常。

Dart提供了Exception和Error类型以及一些子类型来定义异常。不过,还可以自定义异常,只要抛出非空对象作为异常即可,不要求必须是Exception和Error对象,但是一般来说都是抛出Exception和Error类型。

Exception类型

名称说明
DeferredLoadException延迟加载异常
FormartException格式化异常
IntegerDivisionByZeroException整数除零异常
IOExceptionIO异常
IsolateSpawnException隔离产生异常
NullRejectionException空拒绝异常
OSError操作系统错误
TimeoutException超时异常

Error类型

名称说明
AbstractClassInstantiationError抽象类实例化错误
ArgumentError参数错误
AssertionError断言错误
AsyncError异步错误
CastErrorCast错误
ConcurrentModificationError并发修改错误
CyclicInitializationError周期初始错误
FallThroughErrorFall Through错误
JsonUnsupportedObjectErrorjson不支持错误
NoSuchMethodError没有这个方法错误
NullThrownErrorNull错误
OutOfMemoryError内存溢出错误
RemoteError远程错误
StackOverflowError堆栈溢出错误
StateError状态错误
TypeError类型错误
UnimplementedError未实现的错误
UnsupportedError不支持的错误

异常抛出

异常的抛出和Java还是很相像的。

  //抛出Exception对象
  throw new FormatException('格式异常');

  //抛出Error对象
  throw new NullThrownError();

  //抛出任意非null对象
//  throw '这是一个异常';

异常捕获

try {                                                                                    throw new NullThrownError();
//    throw new OutOfMemoryError();
  } on OutOfMemoryError {
    //on 指定异常类型
    print('没有内存了');
//    rethrow; //把捕获的异常给 重新抛出
  } on Error {
    //捕获Error类型
    print('Unknown error catched');
  } on Exception catch (e) {
    //捕获Exception类型
    print('Unknown exception catched');
  } catch (e, s) {
    //catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为StackTrace对象堆栈信息
    print(e);
    print(s);
  }
}

类的概念和Java当中类似。
但是也有很大的区别。

类的构造

//java中写法
class P {
  double x;
  double y;

  P(int x, int y) {
    this.x = x;
    this.y = y;
  }
}

//dart建议写法
class P {
  num x;
  num y;
  Point(this.x, this.y);
}

重定向构造函数

class P { 
  num x; 
  num y; 

  Point(this.x, this.y); 

  //重定向构造函数,使用冒号调用其他构造函数
  P.alongXAxis(num x) : this(x, 0);
}

类的Get和Set方法

class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

命名构造函数

class Rect{
  int _height;//定义成私有成员(前面加下划线),私有成员不能被外部直接访问
  int _width;
 
  Rect(this._height,this._width);//Dart默认构造函数 只能声明一次,Java可以声明多个
  Rect.heigthSet(this._height);//命名构造函数 可以声明多个
  Rect.widthSet(this._width);//命名构造函数 可以声明多个
  Rect.allSet(this._width,this._height);//命名构造函数 可以声明多个
  Rect.allSet2():_height=5,_width=5;//带默认参数的构造方法
  
  //set get属性方法,外部通过访问属性的形式调用该方法
  set setHeight(int value){
    this._height=value;
  }
 
  //getter属性方法,不用括号,外部通过访问属性的形式调用该方法
  get getHeight{
    return _height;
  }
 
  //getter属性方法,不用括号,外部通过访问属性的形式调用该方法
  get Area{
    return _height*_width;
  }
 
  //定义私有方法
  int _area(){
    return _height*_width;
  }
 
  int getArea(){
    return _area();
  }
 
  String getMessage(){
    return('获取传入的高,宽值:$_height $_width 面积计算为:');
  }
}

抽象 和 继承

// 定义父类
abstract class Person{
  String name;
  int age;
 
  Person(this.name, this.age);
 
  Person.second(this.name, this.age);
 
  void show() {
    print('$name $age');
  }
 
  //抽象方法定义规则,要求子类必须继承
  void marry();
}
// 子类继承,必须实现抽象方法
class Boy extends Person{
  double height;
  Boy(String name, int age,double height):super(name,age){
    this.height=height;
  }
 
  //方法重写
  @override
  void show(){
    // super.show();
    print('$name $age $height');
  }
 
  void playBoy(){
    print('男生喜欢打王者荣耀');
  }
 
  @override
  void marry() {
    print('我是一个男生,要找一个女朋友结婚');
  }
 
}

封装 和 多态

dart中的多态体现在方法重写,向上转型

比如上面Boy子类中的方法重写,我们也可以再定义一个Girl子类重写;

向上转型,向下转型这里做一个简单的介绍,具体代码可在我的资源中下载去看

向上转型可以提取公共方法,向下转型可以转化到子类,调用子类方法,向上转型也是一种封装

  • A is B 判断A是否是B类型
  • A as B 把A类型转换为B类型
  if(p is Boy){
    Boy boy=p as Boy;
    boy.playBoy();
  }

接口

dart中类就是接口,和声明抽象类一样,一般是用abstract修饰

abstract class Person {
  void run();
}
class Student implements Person {
  @override
  void run() {
    print("run 执行了。。。")
  }
}

Mixins

Mixins是Dart里面的一个全新概念,简单来说,用来复用多个类之间的代码,减少耦合,换句话来说,可以从中扩展方法(或变量)而不扩展类。

  • 通过mixins实现类似多继承,但是mixins不属于继承,也不属于接口,就是一种新的特性
  • 作为mixins的类只能继承于最终父类Object,不可以继承别的类
  • mixins类不能有构造函数
  • 一个类可以继承于多个mixins

例如有以下关系

  • 工程师 = 软件工程师 + 建筑工程师
  • 教师 = 美术教师 + IT教师
  • 工作者 = 教师 + 工程师

类_示例关系图1

如果我们用Java来实现

//工作者
abstract class Worker {
    public abstract void doWork();//工作者需要工作
}

//工程师
class Engineer extends Worker {
    @Override
    public void doWork() {
        System.out.println("工程师在工作");
    }
}

//教师
class Teacher extends Worker {
    @Override
    public void doWork() {
        System.out.println("教师在教学");
    }
}

//软件工程师
class SoftwareEngineer extends Engineer {}

//建筑工程师
class BuildingEngineer extends Engineer {}

//美术教师
class ArtTeacher extends Teacher {}

//IT教师
class ITTeacher extends Teacher {}

如果用Dart来实现

//工作者
abstract class Worker {
  void doWork();//工作者需要工作
}

//工程师
class Engineer extends Worker {
  void doWork() {
    print('工程师在工作');
  }
}

//教师
class Teacher extends Worker {
  void doWork() {
    print('教师在教学');
  }
}

//软件工程师
class SoftwareEngineer extends Engineer {}

//建筑工程师
class BuildingEngineer extends Engineer {}

//美术教师
class ArtTeacher extends Teacher {}

//IT教师
class ITTeacher extends Teacher {}

从以上来看,似乎Java和Dart没有什么特别大的区别,因为Dart也是单继承

下面,我们再把场景丰富一下

类_示例关系图2

通过图形或表格可以看出,软件工程师和IT教师都具备修电脑的能力,建筑工程师和美术教师都具备手绘的能力,但是这些能力都是他们特有的,不是工程师或者教师具备的能力,所以不能在他们的父类中实现。

如果使用Java,那么我们自然就想到了使用interface。

interface CanFixComputer {
    void fixComputer();
}

interface CanDesignSoftware {
    void designSoftware();
}

//软件工程师
class SoftwareEngineer extends Engineer implements CanFixComputer, CanDesignSoftware {

    @Override
    public void fixComputer() {
        System.out.println("修电脑");
    }
    
    @Override
    public void designSoftware() {
        System.out.println("设计软件");
    }

}

//IT教师
class ITTeacher extends Teacher implements CanFixComputer {

    @Override
    public void fixComputer() {
        System.out.println("修电脑");
    }

}

但是,我们知道Dart当中没有interface的概念,但并不意味着这门语言没有接口,事实上,Dart任何一个类都是接口,你可以实现任何一个类,只需要重写那个类里面的所有具体方法。

如果要用Dart来实现的话,只需要将interface修改成abstract class。

但是我们发现,fixComputer这个接口被继承了两次,并且两次的实现都是一样的,这里就出现了代码重复和冗余的问题。怎么办呢?在java中我们有接口的default实现来解决这个问题(这是一个java8出现的不得已的方案。)

但是,有了mixins之后,这件事就变得不那么难了。

abstract class CanFixComputer {
  void fixComputer() {
    print('修电脑');
  }
}

abstract class CanDesignSoftware {
  void designSoftware() {
    print('设计软件');
  }
}

//软件工程师
class SoftwareEngineer extends Engineer
    with CanFixComputer, CanDesignSoftware {}

//IT教师
class ITTeacher extends Teacher with CanFixComputer {}

main() {
  ITTeacher itTeacher = new ITTeacher();
  itTeacher.doWork();
  itTeacher.fixComputer();
  SoftwareEngineer softwareEngineer = new SoftwareEngineer();
  softwareEngineer.doWork();
  softwareEngineer.fixComputer();
  softwareEngineer.designSoftware();
}

通过以上代码,我们可以看到这里不用implements,更不是extends,而是with

每个具有某项特性的类不再需要具体去实现同样的功能,接口是没法实现功能的,而通过继承的方式虽然能实现功能,但已经有父类,同时不是一个父类,又不能多继承,所以这个时候,Dart的Mixin机制就比Java的接口会高效,开发上层的只需要关心当前需要什么特性,而开发功能模块的关心具体要实现什么功能。

关于顺序的理解

既然是with,那应该也会有顺序的区别。

class First {
  void doPrint() {
    print('First');
  }
}

class Second {
  void doPrint() {
    print('Second');
  }
}

class Father {
  void doPrint() {
    print('Father');
  }
}

class Son1 extends Father with First,Second {
  void doPrint() {
    print('Son1');
  }
}

class Son2 extends Father with First implements Second {
  void doPrint() {
    print('Son2');
  }
}

main() {
  Son1 son1 = new Son1();
  son1.doPrint(); // Son1
  Son2 son2 = new Son2();
  son2.doPrint(); // Son2
}

通过这里,我们可以看到
可以看到,无论是extends、implements还是mixin,优先级最高的是在具体类中的方法。

下一个例子:

class First {
  void doPrint() {
    print('First');
  }
}

class Second {
  void doPrint() {
    print('Second');
  }
}

class Father {
  void doPrint() {
    print('Father');
  }
}

class Son1 extends Father with First,Second {

}

class Son2 extends Father with First implements Second {

}

main() {
  Son1 son1 = new Son1();
  son1.doPrint(); // Second
  Son2 son2 = new Son2();
  son2.doPrint(); // First
}

其实在Son2中implements只是说要实现他的doPrint()方法,这个时候其实具体实现是First中Mixin的具体实现。
而Mixin的具体顺序也是可以从代码倒过来看的,最后mixin的优先级是最高的。


泛型

在Dart当中,有很多的容器对象,在创建对象时都可以定义泛型类型,这一点和Java是一样的。

 var list = List<String>();
  list.add('aaa');
  list.add('bbb');
  list.add('ccc');
  print(list);

  var map = Map<int, String>();
  map[1] = 'aaaa';
  map[2] = 'bbbb';
  map[3] = 'cccc';
  print(map);

和Java的区别

  • Java中的泛型信息是编译时的,泛型信息在运行时是不存在的。
  • Dart的泛型类型是固化的,在运行时也有可以判断的具体类型。

异步

Future

Future与JavaScript中的Promise非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果,要么成功,要么失败。

因为Flutter返回的都是一个Fluter对象,自然就可以采用链式方法。

  • Future.then 任务执行完后的子任务
  • Future.delayed 延迟执行
  • Future.catchError 如果异步任务发生错误,我们可以在catchError中捕获错误。
  • Future.whenComplete 完成的时候调用。
  • Future.wait 等待多个异步任务都执行结束后才进行一些操作。

Async/await

如果业务逻辑中有大量异步依赖的情况,将会出现上面这种在回调里面套回调的情况,过多的嵌套会导致的代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback Hell)。

这个问题在JS当中十分的突出,Dart几乎是同样的问题,然后把相关方法平移过来。所以功能和用法也几乎是相同的。

async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用then方法添加回调函数。
await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。
只有async方法才能使用await关键字调用方法
如果调用别的async方法必须使用await关键字。

Stream

Stream 也是用于接收异步事件数据,和Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。

Stream.fromFutures([
  // 1秒后返回结果
  Future.delayed(new Duration(seconds: 1), () {
    return "hello 1";
  }),
  // 抛出一个异常
  Future.delayed(new Duration(seconds: 2),(){
    throw AssertionError("Error");
  }),
  // 3秒后返回结果
  Future.delayed(new Duration(seconds: 3), () {
    return "hello 3";
  })
]).listen((data){
   print(data);
}, onError: (e){
   print(e.message);
},onDone: (){

});
// 输出
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3

Isolates-隔离

所有Dart代码都在隔离区内运行,而不是线程。每个隔离区都有自己的内存堆,确保不会从任何其他隔离区访问隔离区的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值