Forest Forest
首页
  • 当前版本

    • v1.7.x
  • 历史版本

    • v1.6.x
    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
首页
  • 当前版本

    • v1.7.x
  • 历史版本

    • v1.6.x
    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
  • 入门

    • 🎬 安装配置说明
    • 🏹 Springboot环境安装
    • 📐 Springboot环境配置
    • 🎯 Springboot环境使用
    • 🏹 Springboot3环境安装
    • 📐 Springboot3环境配置
    • 🎯 Springboot3环境使用
    • 🏹 Spring环境安装
    • 📐 Spring环境配置
    • 🎯 Spring环境使用
    • 🏹 Solon环境安装
    • 📐 Solon环境配置
    • 🎯 Solon环境使用
    • 🏹 原生Java环境安装
    • 📐 原生Java环境配置
    • 🎯 原生Java环境使用
    • 🧬 编程式接口
  • 配置项

    • 👜 Springboot环境配置项
    • 👝 Spring环境配置项
    • 👜 Solon环境配置项
    • 🎒 原生Java环境配置项
    • 📚 配置优先级/作用域
  • 声明式接口

    • 🧱 构建接口
    • 🍀 请求方法
    • 🚚 请求地址
    • 🎈 URL 参数
    • 🍭 请求头
    • 👔 请求体
    • 🍮 后端框架
    • 🧁 接口注解
    • 📬 接收数据
    • 🍛 数据转换
    • 🎀 对象字段
    • 🍓 成功/失败条件
    • 🍌 重试机制
    • 🥂 重定向
    • 🍔 Gzip解压
    • 🎂 日志管理
    • ⚽ 回调函数
    • 🍟 异步请求
    • 🛡️ HTTPS
    • 🍪 使用Cookie
    • 🛸 使用代理
    • 🍉 上传下载
    • 🚑 异常处理
  • 编程式接口

    • 请求API

      • 🚀 请求对象
      • 🚢 请求属性
      • ✨ 执行请求
      • 🎊 后端框架
      • 🎪 请求类型
      • 🔮 请求地址
      • 🧀 URL 参数
      • 🚅 请求头
      • 🚋 请求体
      • ⚓ 回调函数
      • 🚁 异步请求
      • 🥯 Cookie
      • 🍜 成功/失败条件
      • 🌶️ 重试机制
      • ⛵ 重定向
      • 🛰️ 请求代理
    • 响应API

      • 🌠 响应对象
      • ✒️ 读取数据
      • 🦋 响应状态码
      • 🏥 响应错误处理
      • 🎧 响应头
      • 🥞 Cookie
  • SSE

    • 🐿 声明式 SSE 接口
    • 🐠 编程式 SSE 接口
    • 🐶 SSE 控制器
    • 🐬 SSE 拦截器
    • 🦄 SSE 事件处理方法
  • 模板表达式

    • 🍬 Hello World
    • 🍹 配置属性引用
    • 🍖 变量引用
    • 🥃 动态变量绑定
    • 🥗 参数序号引用
    • 🍍 引用对象属性
    • 🥝 调用对象方法
    • ⛳️ 空安全
      • 空安全操作符
      • Elvis 表达式
    • 🪆 嵌套字符串模板
  • 高级特性

    • 🥪 拦截器
    • 🍏 自定义注解
    • 🍇 组合注解
    • 🥑 自定义转换器
  • v1.7.x文档
  • 模板表达式
公子骏
2022-07-01
目录

⛳️ 空安全

Forest 字符串模板中的变量引用,默认情况下是不能直接引用一个未定义的变量的

// 若变量 name 未定义,则会直接报错
@Get(url = "http://localhost:8080/{name}")
String send();
1
2
3

# 空安全操作符

但是,自v1.7.1版本之后,Forest字符串模板支持空安全语法,在变量名之后使用空安全操作符(问号 ?),可以让它不再报错,而是直接返回 null 值。

// 若变量 name 未定义,则会直接返回 null
// 若变量 name 有值,则返回它自身的值
@Get(url = "http://localhost:8080/{name?}")
String send();
1
2
3
4

或者,引用了一个不存在的或值为 null 的变量后,再用点.访问它的属性,直接这样写自然是会报错的。然而也可以通过空安全属性访问操作符?.自动判断是否为空。

// 会先判断 a 是否为空,如果 a 为空则直接 null 值,不会再继续解析下去
// 如果 a 不为空,则返回 a.b 的值
@Get(url = "http://localhost:8080/{a?.b}")
String send();
1
2
3
4

使用?.符号连接起来的空安全调用链,无论链路多长,只要其中一个为空,则直接中断并返回 null,不用担心报空指针错误

// 会先判断 a 是否为空,再判断 a.b 是否为空,再判断 a.b.c,..., 一直递归判断到链路的末尾
// 只要其中一个变量或属性值为空,就会立即中断并返回 null
// 如果全不为空,那自然就会返回链路的最后一个属性的值
@Get(url = "http://localhost:8080/{a?.b?.c?.d?.e}")
String send();
1
2
3
4
5

# Elvis 表达式

空安全操作符?和?.的确是能有效解决空指针异常问题,但最后总返回一个 null 值也是很不美观啊。而且有些场景,比如 url 中的参数、或请求头中的参数不能直接传一个 null,而是空字符串,或其他默认值。

这时就可以使用 Elvis 操作符??,也称为是空值合并操作符。简单来说就是在一个变量或一个表达式后面追加两个问号(??),并在它的右边再跟上一个表达式作为左边变量或表达式为空的情况下所返回的默认值

// 如果变量 a 为空或未定义,则返回字符串 ok
// 最后 URL 为 http://localhost:8080/ok
// 若变量 a 不为空,则返回它自己的值
@Get(url = "http://localhost:8080/{a ?? 'ok'}")
String send();
1
2
3
4
5

Elvis 表达式也可以和空安全属性访问操作符?.相结合

// 如果变量 a 为空或未定义,则返回字符串 ok,不会再继续读取 a.b 
// 最后 URL 为 http://localhost:8080/ok
@Get(url = "http://localhost:8080/{a?.b ?? 'ok'}")
String send();
1
2
3
4

安全属性访问操作符?.连接起来的调用链可以无限长,中间只要一个变量或属性值为空,就会直接中断,并返回??符号后面定义的默认值

// 会先判断 a 是否为空,再判断 a.b 是否为空,再判断 a.b.c,..., 一直递归判断到链路的末尾
// 只要其中一个变量或属性值为空,就会立即中断并返回 ok
// 最后 URL 为 http://localhost:8080/ok
// 如果全不为空,那自然就会返回链路的最后一个属性的值
@Get(url = "http://localhost:8080/{a?.b?.c?.d?.e ?? 'ok'}")
String send();
1
2
3
4
5
6

一般会将默认值设置为空字符串''

// 如果变量 a 为空或未定义,则返回空字符串
// 最后 URL 为 http://localhost:8080/
@Get(url = "http://localhost:8080/{a ?? ''}")
String send();

// 效果同上
@Get(url = "http://localhost:8080/{a?.b?.c ?? ''}")
String send();
1
2
3
4
5
6
7
8
帮助我们改善此文档 (opens new window)
上次更新: 2025/06/24, 01:16:57
🥝 调用对象方法
🪆 嵌套字符串模板

← 🥝 调用对象方法 🪆 嵌套字符串模板→

Theme by Vdoing | Copyright © 2016-2025 公子骏 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式