All Articles

Dart和Java的区别

_Dart 2.2.1

首先Dart网站的重要的概念应该看一下:

在学习 Dart 的时候,请牢记下面一些事实和概念

  • 所有能够使用变量引用的都是对象, 每个对象都是一个的实例。在 Dart 中 甚至连 数字、方法和 null 都是对象。所有的对象都继承于 Object 类。
  • 使用静态类型(例如前面示例中的 num ) 可以更清晰的表明你的意图,并且可以让静态分析工具来分析你的代码, 但这并不是牵制性的。(在调试代码的时候你可能注意到 没有指定类型的变量的类型为 dynamic。)
  • Dart 在运行之前会先解析你的代码。你可以通过使用 类型或者编译时常量来帮助 Dart 去捕获异常以及 让代码运行的更高效。
  • Dart 支持顶级方法 (例如 main()),同时还支持在类中定义函数。 (静态函数和实例函数)。 你还可以在方法中定义方法 (嵌套方法或者局部方法)。
  • 同样,Dart 还支持顶级变量,以及 在类中定义变量(静态变量和实例变量)。 实例变量有时候被称之为域(Fields)或者属性(Properties)。
  • 和 Java 不同的是,Dart 没有 publicprotected、 和 private 关键字。如果一个标识符以 (_) 开头,则该标识符 在库内是私有的。详情请参考: 库和可见性
  • 标识符可以以字母或者 _ 下划线开头,后面可以是 其他字符和数字的组合。
  • 有时候 表达式 expression语句 statement 是有区别的,所以这种情况我们会分别指明每种情况。
  • Dart 工具可以指出两种问题:警告和错误。 警告只是说你的代码可能有问题, 但是并不会阻止你的代码执行。 错误可以是编译时错误也可以是运行时错误。遇到编译时错误时,代码将 无法执行;运行时错误将会在运行代码的时候导致一个 异常

变量

  1. 可以使用 var 声明变量( java 10也可以 ) var a = 10;
  2. 另外对于动态类型 Dart 还有dynamic 关键字
  3. Dart 所有变量如果未初始化都为 null ,不像 java int 的默认值是 0, boolean 的默认值是 false
  4. final 表示不可变,const 表示常量,static 表示的意义相同都是可以直接通过类名的方式使用方法和属性

内建类型

  1. 没有float类型,intdouble都是num的子类
  2. String 字符串内部可以使用表达式 ${},(和kotlin的使用方式一致),使用单引号和双引号包围,使用三个单引号或双引号包围的字符可以换行,支持emoji表情
var s = 'string interpolation';
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s4 = "That deserves all caps. ${s.toUpperCase()} is very handy!";
var s5 = '''
You can create
multi-line strings like this one.
''';
var s6 = """This is also a
multi-line string.""";
var clapping = '\u{1f44f}'; //😆
  1. 没有数组只有列表,List, Set, Map 不是抽象接口,可以直接使用,并且支持泛形

    var list = [1, 2, 3]; // 列表
    var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; // Set
    var gifts = {
    // Key:    Value
    'first': 'partridge',
    'second': 'turtledoves',
    'fifth': 'golden rings'
    }; // Map

方法

  1. 支持顶级方法,方法也是对象, 支持 lambda 表达式的写法
  2. 如果方法的参数是解构出来的可以通过 @required 注解标注为必填 const Scrollbar({Key key, @required Widget child})
  3. 支持可选参数,可选参数写在最后并且使用[]包围 String say(String from, String msg, [String device])
  4. 支持默认参数 void enableFlags({bool bold = false, bool hidden = false}) {...}
  5. 支持匿名方法(参数){方法体}
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});
  1. 支持闭包
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

操作符

  1. as , is, is! :as 类似与强制类型转换, is 类似 instanceof
  2. 空替换??String playerName(String name) => name ?? 'Guest'; 等价于String playerName(String name) => name != null ? name : 'Guest';
  3. 级联符号 (..) 可以代替构建者模式

    var button = querySelector('#confirm');
    button.text = 'Confirm';
    button.classes.add('important');
    button.onClick.listen((e) => window.alert('Confirmed!'));
    // 使用级联操作
    querySelector('#confirm') // Get an object.
    ..text = 'Confirm' // Use its members.
    ..classes.add('important')
    ..onClick.listen((e) => window.alert('Confirmed!'));
  4. ?.操作符当对象不为空时调用后面的属性或方法: foo?.a 类似于if( foo != null) f.a;

异常

  1. Dart的异常是不用必须捕获的
  2. try {} catch有点不一样
try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 只捕获 OutOfLlamasException
  buyMoreLlamas();
} on Exception catch (e) {
  // 上面不能捕获的且是Exception的子类
  print('Unknown exception: $e');
} catch (e,s) {
  // 其余的所有异常,s ==》 stack trace
  print('Something really unknown: $e');
 rethrow; //不处理,直接抛出去
}

  1. 创建对象可以不使用new关键字
  2. 可以给构造方法命名
class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}
  1. 调用父类的构造方法(:
class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}
  1. 在构造方法的方法体调用之前初始化属性
import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}
  1. 常量构造方法,在构造方法之前使用const修饰,属性必需是final或者const
class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}
const ca = ImmutablePoint(1,1); // const 修饰的变量 必须是const的构造方法
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // true
  1. factory 修饰的构造方法为工厂方法
class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
  1. runtimeType 关键字 获取变量运行时的类型 print('The type of a is ${a.runtimeType}'); Dart 的泛形是不擦除的
  2. gettersetter: 通过这两个关键字可以自定义属性的值
class Rectangle {
  num left, top, width, height;

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

  // Define two calculated properties: right and bottom.
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}
  1. 没有interfaces关键字,每个类都是一个接口
  2. 支持操作符重载 操作符
  3. 支持重写noSuchMethod()方法,当对象调用不存在的属性或方法时该方法会被调用
  4. 支持混入mixin, 提供by, mixin, mixin ..on 关键字

泛形

  1. Java 运行时会擦除泛形,Dart 不会
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true

库和可见性

  1. Dart 使用 URI 来确定一个库, 可以给库添加前缀(使用 as 关键词)
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
  1. 支持导入部分库(show),或者隐藏部分库(hide)
// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
  1. 支持懒加载 deferred as
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

异步

  1. async, await 关键字, 声明耗时操作,返回值必须是 Future 方法名后用 async 标注, 调用耗时操作时需要使用 await 关键字,并且在 async标注的方法中
Future<String> lookUpVersion() async => '1.0.0';

Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}
  1. Stream 关键字使用 await for 或者 listen方法
Future main() async {
  // ...
  await for (var request in requestServer) {
    handleRequest(request);
  }
  // ...
}

生成器

  1. 方法体使用 sync* 标注, 返回值前添加yeild, 返回值 Iterable 表示同步, Stream 表示异步, 如果返回值为递归使用 yeild * 来提高性能
// 同步
Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}
// 异步
Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}
// 返回值为递归
Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}

可运行的类

  1. 如果类中实现了 call 方法, 那么这个类就是可执行的
class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

main() {
  var wf = new WannabeFunction();
  var out = wf("Hi","there,","gang");
  print('$out');
}

Typedefs

  1. 使用 typedef 关键字 标注方法签名,可以避免方法签名的丢失
typedef Compare = int Function(Object a, Object b);

class SortedCollection {
  Compare compare;

  SortedCollection(this.compare);
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);
  assert(coll.compare is Function);
  assert(coll.compare is Compare);
}

注解

  1. Dart 使用类来声明注解, Java 使用 @interface; 另外 Dart 貌似没有地方声明注解的使用范围

注释

  1. Dart 可以使用 ///, /** 编写文档注释