Java 14或15中的字符串插值

28
自从我使用Java 14和15的预览功能以来,一直在尝试找到Java中的字符串插值。
我找到的最接近的答案是
`String.format("u1=%s;u2=%s;u3=%s;u4=%s;", u1, u2, u3, u4)`
因为我从很多参考资料中得到的答案都是4、5年前的旧答案。在Java 11、12、13、14、15是否有任何关于字符串插值的更新,相当于C#?
string name = "Horace";
int age = 34;
Console.WriteLine($"Your name is {name} and your age {age}");

编辑:JEP 430,该提案涵盖了这个问题以及更多内容,旨在针对JDK 21。

3
似乎Java没有时间花在这些轻浮的功能上。一些语言从一开始就有它,另一些语言甚至在最近的版本中增强了它。但看起来Java总是比日常开发者更清楚如何提高生产力 :) - ernest_k
2
@ernest_k,向已经广泛使用的20多年的编程语言添加语言特性并不是一件容易的事情。即使是像文本块这样“简单”的特性也引起了很多争议(查看一下JEP的历史记录)- 添加内联插值将会引起一场风暴。因为每个人都有自己喜欢的“开发者生产力”功能,而每个人最喜欢的功能也与其他人最喜欢的功能不兼容。 - M. Prokhorov
4
“@ernest_k 我在想,相较于写成“Your name is "+name+" and your age "+age”,你真正通过写$"Your name is {name} and your age {age}"获得了多少生产力。” - Holger
10
关于为什么它是有效的“推理”,我不会浪费时间给你解释。这就像问为什么写3x5比只写3+3+3+3+3更“好”一样。 - birgersp
2
@birgersp 你是认真的吗?你想争辩在源代码中仅仅节省一个字符,再加上一些可以忽略的空格,看起来更有戏剧性的差异,就值得引入新的语言特性吗?在前面评论的例子中,$"Your name is {name} and your age {age}""Your name is "+name+" and your age "+age没有任何区别。这种特性永远无法弥补您在编写此类注释时已经失去的生产力。 - Holger
显示剩余14条评论
6个回答

45

有一个稍微更接近的东西; 一个名为 formatted 的实例版本,它类似于 String :: format

String message = "Hi, %s".formatted(name);

它类似于String::format,但在链接表达式中使用更加友好。


12
似乎很容易被忽略的是,java.util.Formatter有多么昂贵。否则,像Optional.toString()这样的方法就不会被实现为String.format("Optional[%s]", value),而只需简单的"Optional[" + value + "]"即可。在一个新环境中,这种不必要的format使用会触发165个以前未使用的类的加载,这表明了涉及的组件。仅仅为了将数据格式化为区域敏感并输出到任意I/O位置中,却使用一个框架,这种操作就好比开着Falcon X去超市购物一样浪费。 - Holger
在未来的Java版本中是否可以加入该功能? - Mammad Yahyayev

11
据我所知,标准的Java库中没有关于这种字符串格式化的更新。换句话说,你仍然只能使用String.format()和它的基于索引的替换机制,或者选择一些第三方库/框架,比如Velocity、FreeMarker等,详情可以参考这里

5
第三个选项:写 "你的名字是" + name + ",你的年龄是" + age。这种方法对于动态字符串不起作用,但仅仅因为可能会在格式化字符串中引用所有范围内的变量,并不是编译语言的方式。请注意,此翻译并未改变原文的意思。 - Holger

2
目前没有内置的支持,但可以使用Apache Commons TextStringSubstitutor
import org.apache.commons.text.StringSubstitutor;
import java.util.HashMap;
import java.util.Map;
// ...
Map<String, String> values = new HashMap<>();
values.put("animal", "quick brown fox");
values.put("target", "lazy dog");
StringSubstitutor sub = new StringSubstitutor(values);
String result = sub.replace("The ${animal} jumped over the ${target}.");
// "The quick brown fox jumped over the lazy dog."

这个类支持为变量提供默认值。

String result = sub.replace("The number is ${undefined.property:-42}.");
// "The number is 42."

要使用递归变量替换,请调用setEnableSubstitutionInVariables(true);
Map<String, String> values = new HashMap<>();
values.put("b", "c");
values.put("ac", "Test");
StringSubstitutor sub = new StringSubstitutor(values);
sub.setEnableSubstitutionInVariables(true);
String result = sub.replace("${a${b}}");
// "Test"

有两个导入缺失import java.util.HashMap;import java.util.Map;此外,这个导入可能会有用 import org.apache.commons.lang3.StringUtils; - stan

0

你也可以像这样使用MessageFormat(Java 5.0或更高版本)

MessageFormat.format("Hello {0}, how are you. Goodbye {0}",userName);

非常好


@user16320675,真的,我今天才知道MessageFormat,它在Java 15中被提及,所以我决定它出现在Java 15中。 - roma2341
@user16320675,我已经阅读了这个文档 - https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/text/MessageFormat.html。它在谷歌上的标题是“MessageFormat(Java SE 15和JDK 15)”,因此我认为它不适用于早期版本。 - roma2341
1
所有JDK 15 API文档页面都有“JDK 15 API”标题,但您只需要滚动到您链接的页面即可找到[Since: 1.1]。因此,引入此类的不是JDK 15或Java 5.0,而是Java 1.1,换句话说,这个功能几乎从一开始就存在。 - Holger

-1
你可以使用Java的字符串模板功能。 它在JEP 430中有详细描述,并且作为JDK 21的预览功能出现。以下是一个示例用法:
string name = "Horace";
int age = 34;
System.out.println(STR."Your name is {name} and your age {age}");

-2

看起来这些Java版本中没有可用的漂亮的C#风格插值。我们为什么需要它-是为了有漂亮和可读的代码行将文本转储到日志文件中。

下面是可以工作的示例代码(在某些编写时需要注释的org.apache.commons.lang3.StringUtils,但后来不需要了)-它会丢弃ClassNotFound或其他NotFoundException-我没有调查过。

StringSubstitutor可能稍后会被打包成更好的东西,以使其更容易用于Log消息转储

package main;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.text.*;
//import org.apache.commons.lang3.StringUtils;

public class Main {

    public static void main(String[] args) {
        System.out.println("Starting program");
        
        var result =  adding(1.35,2.99);

        Map<String, String> values = new HashMap<>();
        values.put("logMessageString", Double.toString(result) );

        StringSubstitutor sub = new StringSubstitutor(values);
        sub.setEnableSubstitutionInVariables(true);
        String logMessage = sub.replace("LOG result of adding: ${logMessageString}");

        System.out.println(logMessage);
        System.out.println("Ending program");
         
    }
    // it can do many other things but here it is just for prcoessing two variables 
    private static double adding(double a, double b) {
        return a+b;
    }

}

1
Java的日志框架已经内置了这种东西。 - John Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接