网站首页 > 技术文章 正文
让我们考虑以下多行SQL字符串:
UPDATE "public"."office"
SET ("address_first", "address_second", "phone") =
(SELECT "public"."employee"."first_name",
"public"."employee"."last_name", ?
FROM "public"."employee"
WHERE "public"."employee"."job_title" = ?
众所周知,在JDK 8之前,我们可以以多种方式将这段SQL包装成Java字符串(字符串字面量)。
在JDK 8之前
可能最常见的方法是使用众所周知的"+"运算符进行直接连接。这样,我们得到如下的多行字符串表示:
String sql =
"UPDATE \"public\".\"office\"\n"
+ "SET (\"address_first\", \"address_second\", \"phone\") =\n"
+ " (SELECT \"public\".\"employee\".\"first_name\",\n"
+ " \"public\".\"employee\".\"last_name\", ?\n"
+ " FROM \"public\".\"employee\"\n"
+ " WHERE \"public\".\"employee\".\"job_title\" = ?";
编译器应该(并且通常是)足够智能,将"+"操作内部转换为StringBuilder/StringBuffer实例,并使用append()方法来构建最终的字符串。但是,我们可以直接使用StringBuilder(非线程安全)或StringBuffer(线程安全),如以下示例所示:
StringBuilder sql = new StringBuilder();
sql.append("UPDATE \"public\".\"office\"\n")
.append("SET ...\n")
.append(" (SELECT...\n")
// ... 省略其他部分
另一种方法(可能不如前两种流行)是使用String.concat()方法。这是一个不可变操作,基本上将给定的字符串附加到当前字符串的末尾。最后,它返回新的组合字符串。尝试附加null值将导致NullPointerException(在前面的两个示例中,我们可以附加null值而不会引发任何异常)。通过链接concat()调用,我们可以像以下示例一样表示多行字符串:
String sql = "UPDATE \"public\".\"office\"\n"
.concat("SET...\n")
.concat(" (SELECT...\n")
// ... 省略其他部分
进一步来说,我们有String.format()方法。只需使用%s格式说明符,我们就可以在多行字符串中连接多个字符串(包括null值),如下所示:
String sql = String.format("%s%s%s%s%s%s",
"UPDATE \"public\".\"office\"\n",
"SET ...\n",
" (SELECT ...\n",
// ... 省略其他部分
虽然这些方法如今仍然很流行,但让我们看看JDK 8在这个话题上有什么要说的。
从JDK 8开始
从JDK 8开始,我们可以使用String.join()方法来表示多行字符串。此方法也专门用于字符串连接,它允许我们的示例具有清晰的可读性。如何实现?此方法将分隔符作为第一个参数,并在要连接的字符串之间使用此分隔符。因此,如果我们认为\n是我们的行分隔符,那么它只需要指定一次,如下所示:
String sql = String.join("\n",
"UPDATE \"public\".\"office\"",
"SET (\"address_first\", \"address_second\", \"phone\") =",
" (SELECT \"public\".\"employee\".\"first_name\",",
" \"public\".\"employee\".\"last_name\", ?",
" FROM \"public\".\"employee\"",
" WHERE \"public\".\"employee\".\"job_title\" = ?;");
除了String.join()方法外,JDK 8还提供了java.util.StringJoiner。StringJoiner支持分隔符(如String.join())但也支持前缀和后缀。表达我们的多行SQL字符串不需要前缀/后缀;因此分隔符仍然是我们最喜欢的功能:
StringJoiner sql = new StringJoiner("\n");
sql.add("UPDATE \"public\".\"office\"")
.add("SET (\"address_first\", ..., \"phone\") =")
.add(" (SELECT \"public\".\"employee\".\"first_name\",")
// ... 省略其他部分
最后,谈到JDK 8就不能不提它的强大的Stream API。更具体地说,我们对Collectors.joining()收集器感兴趣。这个收集器的工作方式与String.join()相同,在我们的例子中,它看起来像这样:
String sql = Stream.of(
"UPDATE \"public\".\"office\"",
"SET (\"address_first\", \"address_second\", \"phone\") =",
" (SELECT \"public\".\"employee\".\"first_name\",",
" \"public\".\"employee\".\"last_name\", ?",
" FROM \"public\".\"employee\"",
" WHERE \"public\".\"employee\".\"job_title\" = ?;")
.collect(Collectors.joining(String.valueOf("\n")));
所有前面的示例都有一个共同的缺点。最重要的是,这些示例中没有一个是真正的多行字符串字面量,每行之间的转义字符和额外引号严重影响了可读性。幸运的是,从JDK 13(作为未来预览)到JDK 15(作为最终功能),新的文本块已成为表示多行字符串字面量的标准。让我们看看如何实现。
引入文本块(JDK 13/15)
JDK 13(JEP 355)引入了一个预览功能,旨在为多行字符串字面量提供支持。在JDK 15(JEP 378)的两个版本中,文本块功能已成为最终且永久可用的功能。但是,让我们快速看看文本块如何塑造我们的多行SQL字符串:
String sql="""
UPDATE "public"."office"
SET ("address_first", "address_second", "phone") =
(SELECT "public"."employee"."first_name",
"public"."employee"."last_name", ?
FROM "public"."employee"
WHERE "public"."employee"."job_title" = ?""";
这太棒了,对吧?!我们立即注意到SQL的可读性已经恢复,我们没有混淆分隔符、行终止符和连接。文本块简洁、易于更新且易于理解。在SQL字符串中额外的代码足迹为零,Java编译器将尽最大努力以尽可能可预测的方式创建字符串。以下是嵌入JSON信息的另一个示例:
String json = """
{
"widget": {
"debug": "on",
"window": {
"title": "Sample Widget 1",
"name": "back_window"
},
// ... 省略其他部分
}""";
那么,如何用文本块表示HTML呢?
String html = """
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>John</td>
<td>Smith</td>
<!-- 这里有一个错误,缺少年龄单元格 -->
</tr>
</table>"""; // 注意这里修正了原始代码中的错误,应该是</table>而不是<table>
挂接文本块语法
文本块的语法相当简单。没有花哨的东西,也没有复杂的事情,只需要记住两个方面:
1. 文本块必须以"""(即三个双引号)和换行符开始。我们称此构造为开放分隔符。
2. 文本块必须以"""(即三个双引号)结束。"""可以单独放在一行(作为新行)或放在文本的最后一行末尾(如我们的示例所示)。我们称此构造为关闭分隔符。但是,这两种方法之间存在语义差异(在下一个问题中详细讨论)。
在此上下文中,以下示例在语法上是正确的:
String tb = """
I'm a text block""";
String tb = """
I'm a text block
""";
// ... 其他正确示例
另一方面,以下示例是不正确的,并会导致编译器错误:
String tb = """I'm a text block"""; // 错误:缺少换行符
// ... 其他错误示例
但是,请考虑以下最佳实践。
通过查看前面的代码片段,我们可以为文本块塑造一个最佳实践:仅在您有多行字符串时使用文本块;如果字符串适合单行代码(如前面的代码片段所示),则使用普通字符串字面量,因为使用文本块不会增加任何显著价值。
在捆绑的代码中,您可以在SQL、JSON和HTML的片段上实践本问题中的所有示例。
对于第三方库支持,请考虑:Apache Commons, StringUtils.join(), 和 Guava Joiner.on()。
接下来,让我们专注于处理文本块分隔符。
猜你喜欢
- 2024-09-14 Mysql:替换某个字段中的部分字符串——replace函数
- 2024-09-14 plsql字符串分割浅谈(plsql字符串截取)
- 2024-09-14 oracle函数--INSTR、SUBSTR使用说明和实例讲解
- 2024-09-14 详解Oracle使用substr和instr截取字符串指定位置的字符
- 2024-09-14 mysql 替换某一个字段中的字符串(mysql替换一个字符串的字符函数为)
- 2024-09-14 sql注入总结(sql注入示例)
- 2024-09-14 Mybatis 中的 DAO 接口和 XML 文件里的 SQL他们如何建立关系?
- 2024-09-14 SQL Server - 字符串常用操作(sqlserver 字符类型)
- 2024-09-14 如何在Java中比较字符串?(如何在java中比较字符串个数)
- 2024-09-14 SQL截取函数(substr)与字符串查找函数(Instr)的组合应用
- 1512℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 556℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 504℃MySQL service启动脚本浅析(r12笔记第59天)
- 482℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 480℃启用MySQL查询缓存(mysql8.0查询缓存)
- 460℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 440℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 438℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)