在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

概述

在实际开发中,JSON解析过程中可能遇到各种错误,如格式错误、类型不匹配、字段缺失等。完善的错误处理机制是保证应用稳定性的关键。本文将详细介绍JSON解析中常见的错误类型、捕获策略和容错机制,帮助开发者构建健壮的应用。

1. JSON解析常见错误类型

1.1 FormatException - 格式错误

当JSON字符串不符合语法规范时抛出:

// 错误示例1:缺少引号
String invalidJson1 = '{"name": 张三}';

// 错误示例2:多余逗号
String invalidJson2 = '{"name": "张三",}';

// 错误示例3:缺少闭合括号
String invalidJson3 = '{"name": "张三"';

1.2 TypeError - 类型错误

当类型转换失败时抛出:

Map<String, dynamic> data = {'age': '25'};
int age = data['age'] as int; // TypeError: String cannot be cast to int

1.3 NullError - 空值错误

当访问null对象的属性时抛出:

Map<String, dynamic> data = {'user': null};
Map<String, dynamic> user = data['user'] as Map<String, dynamic>; // 可能导致错误

1.4 RangeError - 范围错误

当访问数组越界时抛出:

List<dynamic> list = [1, 2, 3];
var item = list[5]; // RangeError

2. 错误捕获策略

2.1 基础try-catch

void parseJson(String jsonString) {
  try {
    Map<String, dynamic> data = jsonDecode(jsonString);
    String name = data['name'] as String;
    print('解析成功: $name');
  } catch (e) {
    print('解析失败: $e');
  }
}

2.2 分类捕获

void parseJson(String jsonString) {
  try {
    Map<String, dynamic> data = jsonDecode(jsonString);
    String name = data['name'] as String;
    int age = data['age'] as int;
    print('解析成功');
  } on FormatException catch (e) {
    print('JSON格式错误: $e');
  } on TypeError catch (e) {
    print('类型转换错误: $e');
  } on Exception catch (e) {
    print('其他异常: $e');
  } catch (e) {
    print('未知错误: $e');
  }
}

2.3 使用rethrow重新抛出

void parseJson(String jsonString) {
  try {
    Map<String, dynamic> data = jsonDecode(jsonString);
  } catch (e) {
    print('记录错误日志: $e');
    rethrow; // 重新抛出,让上层处理
  }
}

3. 容错解析模式

3.1 安全类型转换

String? safeString(dynamic value) {
  if (value is String) {
    return value;
  }
  return null;
}

int? safeInt(dynamic value) {
  if (value is int) {
    return value;
  }
  if (value is double) {
    return value.toInt();
  }
  return null;
}

3.2 默认值处理

factory Weather.fromJson(Map<String, dynamic> json) {
  return Weather(
    city: json['city'] as String? ?? '未知城市',
    temperature: (json['temperature'] as num?)?.toInt() ?? 0,
    humidity: (json['humidity'] as num?)?.toInt() ?? 50,
  );
}

3.3 可选字段处理

class Weather {
  final String city;
  final int temperature;
  final String? description; // 可选字段
  
  Weather({
    required this.city,
    required this.temperature,
    this.description,
  });
  
  factory Weather.fromJson(Map<String, dynamic> json) {
    return Weather(
      city: json['city'] as String? ?? '未知城市',
      temperature: (json['temperature'] as num?)?.toInt() ?? 0,
      description: json['description'] as String?,
    );
  }
}

3.4 嵌套对象容错

factory Weather.fromJson(Map<String, dynamic> json) {
  return Weather(
    city: json['city'] as String? ?? '未知城市',
    wind: _parseWind(json['wind']),
  );
}

static Wind _parseWind(dynamic json) {
  if (json is Map<String, dynamic>) {
    return Wind.fromJson(json);
  }
  return Wind(direction: '未知', speed: 0);
}

3.5 数组容错

static List<Forecast> _parseForecast(dynamic json) {
  if (json is List<dynamic>) {
    return json
        .whereType<Map<String, dynamic>>()
        .map((e) => Forecast.fromJson(e))
        .toList();
  }
  return [];
}

4. 错误处理最佳实践

4.1 创建统一的错误处理类

class JsonParseError {
  final String message;
  final String? field;
  final dynamic rawValue;
  final StackTrace? stackTrace;
  
  JsonParseError({
    required this.message,
    this.field,
    this.rawValue,
    this.stackTrace,
  });
  
  
  String toString() {
    return 'JsonParseError: $message${field != null ? ' (字段: $field)' : ''}';
  }
}

4.2 使用Result模式

enum ParseStatus { success, failure }

class ParseResult<T> {
  final ParseStatus status;
  final T? data;
  final JsonParseError? error;
  
  ParseResult.success(this.data) 
      : status = ParseStatus.success, 
        error = null;
  
  ParseResult.failure(this.error) 
      : status = ParseStatus.failure, 
        data = null;
}

ParseResult<Weather> parseWeather(String jsonString) {
  try {
    Map<String, dynamic> data = jsonDecode(jsonString);
    Weather weather = Weather.fromJson(data);
    return ParseResult.success(weather);
  } on FormatException catch (e) {
    return ParseResult.failure(
      JsonParseError(message: 'JSON格式错误: $e'),
    );
  } on TypeError catch (e) {
    return ParseResult.failure(
      JsonParseError(message: '类型转换错误: $e'),
    );
  }
}

4.3 错误日志记录

void logError(dynamic error, StackTrace stackTrace, String context) {
  print('[$context] 错误: $error');
  print('堆栈: $stackTrace');
  // 可以发送到远程日志服务
}

5. 完整示例:容错解析器

import 'dart:convert';

class Weather {
  final String city;
  final int temperature;
  final int humidity;
  final Wind? wind;
  final List<Forecast> forecast;
  
  Weather({
    required this.city,
    required this.temperature,
    required this.humidity,
    this.wind,
    required this.forecast,
  });
  
  factory Weather.fromJson(Map<String, dynamic> json) {
    return Weather(
      city: _parseString(json['city'], '城市'),
      temperature: _parseInt(json['temperature'], '温度'),
      humidity: _parseInt(json['humidity'], '湿度'),
      wind: _parseWind(json['wind']),
      forecast: _parseForecast(json['forecast']),
    );
  }
  
  static String _parseString(dynamic value, String fieldName) {
    if (value is String) {
      return value;
    }
    print('警告: $fieldName 类型错误,使用默认值');
    return '未知';
  }
  
  static int _parseInt(dynamic value, String fieldName) {
    if (value is int) {
      return value;
    }
    if (value is double) {
      return value.toInt();
    }
    print('警告: $fieldName 类型错误,使用默认值');
    return 0;
  }
  
  static Wind? _parseWind(dynamic json) {
    if (json is Map<String, dynamic>) {
      return Wind.fromJson(json);
    }
    return null;
  }
  
  static List<Forecast> _parseForecast(dynamic json) {
    if (json is List<dynamic>) {
      return json
          .whereType<Map<String, dynamic>>()
          .map((e) => Forecast.fromJson(e))
          .toList();
    }
    return [];
  }
}

class Wind {
  final String direction;
  final int speed;
  
  Wind({required this.direction, required this.speed});
  
  factory Wind.fromJson(Map<String, dynamic> json) {
    return Wind(
      direction: json['direction'] as String? ?? '未知',
      speed: (json['speed'] as num?)?.toInt() ?? 0,
    );
  }
}

class Forecast {
  final String date;
  final int high;
  final int low;
  
  Forecast({required this.date, required this.high, required this.low});
  
  factory Forecast.fromJson(Map<String, dynamic> json) {
    return Forecast(
      date: json['date'] as String? ?? '未知日期',
      high: (json['high'] as num?)?.toInt() ?? 0,
      low: (json['low'] as num?)?.toInt() ?? 0,
    );
  }
}

6. 鸿蒙平台错误处理

6.1 平台特定错误

在鸿蒙平台上,需要注意以下特殊情况:

  • 网络请求超时导致的不完整JSON
  • 平台特定的字符编码问题
  • 内存限制导致的大型JSON解析失败

6.2 异步错误处理

Future<Weather?> fetchWeather(String url) async {
  try {
    final response = await http.get(Uri.parse(url));
    
    if (response.statusCode != 200) {
      throw Exception('HTTP错误: ${response.statusCode}');
    }
    
    return Weather.fromJson(jsonDecode(response.body));
    
  } on SocketException catch (e) {
    print('网络连接错误: $e');
    return null;
  } on FormatException catch (e) {
    print('JSON格式错误: $e');
    return null;
  } catch (e) {
    print('未知错误: $e');
    return null;
  }
}

7. 总结

完善的错误处理机制是构建健壮应用的关键。通过分类捕获异常、安全类型转换、提供默认值等策略,可以有效提高JSON解析的容错能力。在鸿蒙平台上,还需要考虑网络和平台特定的错误情况。下一章将介绍JSON格式化与美化的方法。

核心知识点回顾

  1. JSON解析常见错误:FormatException、TypeError、NullError、RangeError
  2. 使用try-catch进行错误捕获,分类处理不同类型的异常
  3. 使用as?进行安全类型转换,避免TypeError
  4. 使用??提供默认值,处理缺失或null字段
  5. 对于嵌套对象和数组,提供容错解析逻辑
  6. 使用Result模式统一处理成功和失败状态
  7. 添加错误日志记录,便于问题排查
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐