[Flutter]足够入门的Dart语言系列之流程控制语句:中断和异常(continue/break、try...catch)

简介: 循环的执行是通过循环条件来控制的,但是,有时我们想要通过额外的条件判断,来决定是否中断执行,或者中断本次循环而继续执行下次及之后的循环;此外,我们需要对于异常情况的处理...

中断流程

循环的执行是通过循环条件来控制的,但是,有时我们想要通过额外的条件判断,来决定是否中断执行,或者中断本次循环而继续执行下次及之后的循环。

这就引出了continuebreakreturn关键字。

return 不仅用于循环的终止,其主要用于函数的返回,或者,整个代码执行的返回(不执行后续代码)。

continue跳转执行下一次的循环

continue表示中止本次循环,继续之后的循环处理。

下面的示例,当i为偶数时,则不执行后面的代码,而是结束当前循环,跳到下一次的循环处理。

i.isEven 判断是否是偶数
int sum = 0;
for (int i = 0; i < 10; i++) {
  if(i.isEven){// 如果是偶数
    continue; // 直接跳转到下一次循环
  }
  sum += i; 
  print("第 $i 次循环,计入 sum");
}
print("sum: $sum");

上面用于在偶数时不执行后面的循环体,而是跳到下一次循环,最终输出如下结果:

第 1 次循环,计入 sum
第 3 次循环,计入 sum
第 5 次循环,计入 sum
第 7 次循环,计入 sum
第 9 次循环,计入 sum
sum: 25

break结束整个循环

break用来结束整个循环。是在循环条件之外结束循环的方式。

比如,在一个While(true)循环中,当条件满足时执行break结束循环,否则会一直死循环下去。

var sum = 1;
var count = 0;
while (true) {
  if (sum > 100) {
    break;
  }
  sum += sum;
  count++;
}

print("sum是:$sum");
print("加总的次数为:$count");

输出结果:

sum是:128
加总的次数为:7

return当前函数

return主要用于返回当前函数,表示之后的代码均不执行,而是返回(通常会返回数据)。如果用在循环中,起到结束循环、整个代码返回作用。

比如,还是上一次的循环,将终止条件改为return,后续的代码将不会执行,产生Dead code

var sum = 1;
var count = 0;
while (true) {
  if (sum > 100) {
    return;
  }
  sum += sum;
  count++;
}

print("sum是:$sum");
print("加总的次数为:$count");

异常流程

异常是相对于正常处理流程中出现的意外,通常是可预见的,比如网络异常、文件读取异常、日期格式化异常、数值越界异常、数据值异常等。

发生异常,如果不处理,整个执行流程(或程序)就有可能因错误而停止或崩溃,无法执行之后的任务。

异常捕获就是对可能出现的错误进行捕捉,然后处理或记录异常情况,保证程序后续的执行。同时,异常信息的记录,可以更容易的定位问题的发生原因。

异常流程通常用try...catch...捕获异常,来处理对应的错误。

Dart的所有异常都是非必检异常,除了自定义异常,Dart中可以将任何非null对象作为异常抛出(通常不推荐)。

异常的捕获

如下,在task1方法中,将参数转换为int类型,但是由于传入的字符串不能转换为数字,将会发生转换异常。

void main(){
  task1('a');
  task2();
}

int task1(String num){
  return int.parse(num);
}

void task2(){
  print("Task2");
}

执行时会产生未捕获或未处理的异常:

Uncaught Error: FormatException: a

使用try...catch...捕获异常,catch可以获取异常回调的两个参数。

  • e 表示异常对象,此处为 FormatException
  • s 是 _StackTrace 对象,用于记录异常的栈信息

如下,捕获异常并输出异常类型和异常的堆栈信息:

void main(){
  try{
    task1('a');
  }catch(e,s){
    print("${e.runtimeType}: ${e.toString()}"); 
    print("${s.runtimeType}: ${s.toString()}"); 
  }
  task2(); // Task2
}

int task1(String num){
  return int.parse(num);
}

void task2(){
  print("Task2");
}

结果如下。通过 e 可以看出异常的信息,通过 s 可以看出发生错误时方法栈的情况,便于快速定位到异常发生的地点。

FormatException: FormatException: a
_StackTrace: FormatException: a
    at Object.wrapException (<anonymous>:344:17)
    at Object.int_parse (<anonymous>:2438:15)
    at main (<anonymous>:2595:11)
    at <anonymous>:3217:7
    at <anonymous>:3200:7
    at dartProgram (<anonymous>:3211:5)
    at <anonymous>:3219:3
    at replaceJavaScript (https://www.dartpad.dev/scripts/frame.js:19:19)
    at messageHandler (https://www.dartpad.dev/scripts/frame.js:80:13)
Task2

由于捕获了错误,之后task2();继续执行。

抛出异常

与异常捕获同样重要的是“抛出异常”。

在编写很多方法或类库时,如果遇到不符合条件的情况,我们需要抛出异常,即停止程序的执行,或者交由外部代码来处理异常的情况。

异常抛出,通常都是遇到代码无法执行的情况时,以异常的形式告知停止代码的执行。需要处理修正异常情况后,才能真正的执行。

如下,在函数GetMyDate中,如果有问题,抛出throw FormatException异常:

void main(){
  GetMyDate('2022-10-10');

  GetMyDate('2022-10');
}

List<String> GetMyDate(String myDate){
  var result=myDate.split('-');
  if(result.length!=3){
    throw FormatException('格式不正确,日期字符串必须为`yyyy-(M)M-(d)d`');
  }
  return result;
}

dart中除数为0不会报错

如下,除以0时:

var a=0;
var b=10;
var c=b/a;

print(c); // Infinity

和js中一样,除数为0时不会报错,其结果为Infinity

自定义异常与捕获特定类型的异常

异常的顶层抽象类是 Exception ,通过其 factory 构造可以创建Exception 对象,本质上创建的运行时类型是 _Exception ,可传入一个对象用于表示异常信息。

以上面的除数为0作为示例,我们在除法计算中,判断如果除数为0,则抛出一个异常:

double DivideMethod(int a,int b){
  if(b==0){
    throw Exception('除数不能为0');
  }
  return a/b;
}

以上的抛出异常都是使用的Dart自带异常对象,有时我们需要自定义不同的异常,比如自定义一个除数异常DivideException

double DivideMethod(int a,int b){
  if(b==0){
    throw DivideException(b);
  }
  return a/b;
}

class DivideException implements Exception{
  final int arg;

  DivideException(this.arg);

  @override
  String toString() => "除数不能为$arg";
}

测试,并捕获特定的DivideException

try{
  DivideMethod(10, 0);
}
on DivideException catch(e,s){
  print("${e.runtimeType}: ${e.toString()}");
  print("${s.runtimeType}: ${s.toString()}");
} catch (e,s) {
  // 其余异常处理
}

输出:

DivideException: 除数不能为0
_StackTrace: #0      DivideMethod (file:///E:/privateboolnote/CMLearningCode/Flutter/test/test.dart:30:5)
#1      main (file:///E:/privateboolnote/CMLearningCode/Flutter/test/test.dart:11:5)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#3      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
on TypeException catch 用于捕获特定类型 TypeException的异常。

仅捕获异常,而不获取异常参数。

try{
  DivideMethod(10, 0);
}
on DivideException {
  print("发生了异常");
} catch (e) {
  // 其余异常处理
}

rethrow将捕获的异常再次抛出。

finally语句

无论是否抛出异常,finally语句始终执行,通常finally放在catch语句之后。用于处理一些必须的清理操作,不管是否有异常,均会被执行。

try{
  DivideMethod(10, 0);
} catch (e) {
  // 异常处理
}
finally{
  print('执行必需的清理操作');
}

如果没有指定 catch 语句来捕获异常,则异常会在执行完 finally 语句后抛出:

try{
  DivideMethod(10, 0);
} finally{
  print('执行必需的清理操作');
}

关于Error类型

在Dart中,除了抛出Exception类型外,还可以抛出Error类型(及其子类型),其更多的表示程序运行的失败,这些失败应该被避免。

比如最常见的参数不为空的错误:

throw ArgumentError.notNull('参数不为空的Error');

输出:

Unhandled exception:
Invalid argument(s) (参数不为空的Error): Must not be null
#0      test (file:///E:/privateboolnote/CMLearningCode/Flutter/test/test2.dart:27:5)
#1      main (file:///E:/privateboolnote/CMLearningCode/Flutter/test/test2.dart:21:3)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#3      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

或,其他的参数错误,打印出错误相关的值:

throw ArgumentError.value(i,'参数不能小于0');
Unhandled exception:
Invalid argument (参数不能小于0): -1

参考

相关文章
|
18小时前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
【4月更文挑战第30天】Dart是Google为Flutter框架打造的高效编程语言,具有易学性、接口、混入、抽象类等特性。本文概述了Dart的基础语法,包括静态类型(如int、String)、控制流程(条件、循环)、函数、面向对象(类与对象)和异常处理。此外,还介绍了库导入与模块使用,帮助开发者快速入门Flutter开发。通过学习Dart,开发者能创建高性能的应用。
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
|
1天前
|
Dart 测试技术 UED
Dart 和 Flutter 错误处理指南 | 最佳实践全解析
深入探索 Dart 和 Flutter 中的错误处理技术,从编译时错误到运行时异常,带你学习如何优雅地处理应用程序中的各种意外情况。了解最佳实践,让你的应用程序稳如磐石,用户体验持续优化!
Dart 和 Flutter 错误处理指南 | 最佳实践全解析
|
4天前
|
存储 缓存 开发框架
Flutter的网络请求:使用Dart进行HTTP请求的技术详解
【4月更文挑战第26天】了解Flutter网络请求,本文详述使用Dart进行HTTP请求
|
4天前
|
开发框架 Dart Java
Flutter的核心:Dart语言基础——语法与特性深度解析
【4月更文挑战第26天】Flutter框架背后的Dart语言,以其简洁的语法和独特特性深受开发者喜爱。本文深入解析Dart的语法与特性,如类型推导、动态静态类型系统、统一的类接口、访问权限控制以及并发编程支持。了解并掌握Dart,能助开发者更高效地利用Flutter构建高性能移动应用。
|
3月前
|
Dart JavaScript
Flutter - Dart 基础(数据类型)
【2月更文挑战第3天】
67 1
|
3月前
|
Dart JavaScript 安全
|
3月前
|
Dart Shell 开发工具
解决windows安装Flutter时出现Unknown operating system. Cannot install Dart SDK.问题
解决windows安装Flutter时出现Unknown operating system. Cannot install Dart SDK.问题
|
9月前
|
开发框架 Dart Java
Flutter中Dart语言常用知识
@[TOC](目录) Flutter 是一种使用 Dart 语言开发的跨平台移动应用程序框架。在 Flutter 中,Dart 语言是主要的编程语言,它提供了许多强大的功能和语法糖,可以让开发者更轻松地构建高性能、美观的应用程序。下面是 Flutter 中 Dart 语言的一些详细介绍和代码示例: # 1. 变量和数据类型 在 Dart 语言中,变量不需要声明,可以直接赋值。Dart 语言支持多种数据类型,包括整数、浮点数、布尔值、字符串、列表、映射等。例如: ```dart int a = 10; double b = 3.14; bool c = true; String
|
Dart 索引
[Flutter]足够入门的Dart语言系列之变量的类型:bool、String、num、List、Set和Map
变量的类型指的是变量的特性或特征,比如表示数字类型、文本类型、集合类型等,表示的是一类数据。 Dart提供以下类型:int, double、String、List、Set、Map、null...
556 0
[Flutter]足够入门的Dart语言系列之变量的类型:bool、String、num、List、Set和Map
|
Dart Java Linux
【Flutter】Dart 语言 ( Dart 语言特征 | JIT 即时编译 | AOT 静态编译 )
【Flutter】Dart 语言 ( Dart 语言特征 | JIT 即时编译 | AOT 静态编译 )
251 0