Printf在1.5版本中添加到Java,但我似乎找不到如何将输出发送到字符串而不是文件(这是sprintf在C中所做的)。有人知道如何做到这一点吗?
// Store the formatted string in 'result'
String result = String.format("%4d", i * j);
// Write the result to standard output
System.out.println( result );
请参阅format及其语法
字符串是不可变类型。你不能修改它们,只能返回新的字符串实例。
正因为如此,使用实例方法格式化没有什么意义,因为它必须像这样调用:
String formatted = "%s: %s".format(key, value);
最初的Java作者(和。net作者)认为静态方法在这种情况下更有意义,因为您不需要修改目标,而是调用一个格式方法并传入一个输入字符串。
下面是一个例子,说明为什么format()作为一个实例方法是愚蠢的。在. net中(也可能在Java中),Replace()是一个实例方法。
你可以这样做:
"I Like Wine".Replace("Wine","Beer");
然而,什么也不会发生,因为字符串是不可变的。Replace()尝试返回一个新字符串,但它没有赋值给任何对象。
这会导致很多常见的新手错误,比如:
inputText.Replace(" ", "%20");
同样,什么也不会发生,相反,你必须做:
inputText = inputText.Replace(" ","%20");
现在,如果你明白字符串是不可变的,这就说得通了。如果你没有,那么你只是困惑。Replace()的正确位置应该是format()所在的位置,作为String的静态方法:
inputText = String.Replace(inputText, " ", "%20");
现在发生了什么是毫无疑问的。
真正的问题是,为什么这些框架的作者决定一个应该是实例方法,而另一个应该是静态方法?在我看来,这两种方法都可以更优雅地表示为静态方法。
不管您的观点如何,事实是使用静态版本更不容易犯错误,并且代码更容易理解(没有隐藏的陷阱)。
当然,有一些方法作为实例方法是完美的,比如string。length ()
int length = "123".Length();
在这种情况下,很明显我们并没有试图修改“123”,我们只是检查它,并返回它的长度。这是实例方法的理想候选。
我对不可变对象的实例方法的简单规则:
如果需要返回相同类型的新实例,请使用静态方法。 否则,使用实例方法。
这两种解决方案都可以模拟printf,但方式不同。 例如,要将一个值转换为十六进制字符串,你有以下两个解决方案:
with format(), closest to sprintf(): final static String HexChars = "0123456789abcdef"; public static String getHexQuad(long v) { String ret; if(v > 0xffff) ret = getHexQuad(v >> 16); else ret = ""; ret += String.format("%c%c%c%c", HexChars.charAt((int) ((v >> 12) & 0x0f)), HexChars.charAt((int) ((v >> 8) & 0x0f)), HexChars.charAt((int) ((v >> 4) & 0x0f)), HexChars.charAt((int) ( v & 0x0f))); return ret; } with replace(char oldchar , char newchar), somewhat faster but pretty limited: ... ret += "ABCD". replace('A', HexChars.charAt((int) ((v >> 12) & 0x0f))). replace('B', HexChars.charAt((int) ((v >> 8) & 0x0f))). replace('C', HexChars.charAt((int) ((v >> 4) & 0x0f))). replace('D', HexChars.charAt((int) ( v & 0x0f))); ... There is a third solution consisting of just adding the char to ret one by one (char are numbers that add to each other!) such as in: ... ret += HexChars.charAt((int) ((v >> 12) & 0x0f))); ret += HexChars.charAt((int) ((v >> 8) & 0x0f))); ...
...但那就太难看了。
你可以用PrintStream对任何输出流做printf。 就像这样,打印到字符串流中:
PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());
这输出下面的文本有一个hello从3个朋友 字符串流可以像这样创建ByteArrayOutputStream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
你可以积累很多格式:
PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s ", "hello", 3, "friends");
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());
输出有来自3个朋友的问候和来自一个女孩的2个吻 调用ByteArrayOutputStream上的重置来生成一个干净的新字符串
ps.printf("there is a %s from %d %s", "flip", 5, "haters");
baos.reset(); //need reset to write new string
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());
输出是一个女孩的2个吻
从Java 13开始,你已经格式化了String上的1个方法,它与文本块一起添加作为预览功能2。 你可以用它来代替String.format()
Assertions.assertEquals(
"%s %d %.3f".formatted("foo", 123, 7.89),
"foo 123 7.890"
);
推荐文章
- 指定的子节点已经有一个父节点。你必须先在子对象的父对象上调用removeView() (Android)
- bash:错误的替换
- 在c#中检查字符串是否只包含数字的最快方法
- 对于一个布尔字段,它的getter/setter的命名约定是什么?
- 如何获得当前屏幕方向?
- 如何在Android中渲染PDF文件
- 如何计算一个元素在列表中出现的次数
- c++中类似于java的instanceof
- 我怎么能强迫一个长字符串没有任何空白被包装?
- 我如何解决错误“minCompileSdk(31)指定在一个依赖的AAR元数据”在本机Java或Kotlin?
- 如何POST表单数据与Spring RestTemplate?
- Mockito中检测到未完成的存根
- 转换JSON字符串到JSON对象c#
- 我应该如何复制字符串在Java?
- “while(true)”循环有那么糟糕吗?