我正在遍历 HashMap(有关更多详细信息,请参阅我之前的问题)并构建一个由 Map 中包含的数据组成的字符串。对于每个项目,我都会有一个新行,但对于最后一个项目,我不想要新行。我怎样才能做到这一点?我在想我可以通过某种方式检查条目是否是最后一个条目,但我不确定如何实际做到这一点。
谢谢!
将您的思维过程从“除了最后一次之外都添加换行符”更改为“除了第一次之外都添加换行符”:
boolean first = true;
StringBuilder builder = new StringBuilder();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
if (first) {
first = false;
} else {
builder.append("\n"); // Or whatever break you want
}
builder.append(entry.key())
.append(": ")
.append(entry.value());
}
一种方法(向 Jon Skeet 道歉,因为他借用了他的部分 Java 代码):
StringBuilder result = new StringBuilder();
string newline = "";
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
result.append(newline)
.append(entry.key())
.append(": ")
.append(entry.value());
newline = "\n";
}
那这个呢?
StringBuilder result = new StringBuilder();
for(Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
builder.append(entry.key())
.append(": ")
.append(entry.value())
.append("\n");
}
return builder.substring(0, builder.length()-1);
必须道歉,并感谢 Jon 和 Joel 从他们的例子中“借鉴”。
通常对于这类事情,我使用 apache-commons-lang StringUtils#join。虽然编写所有这些实用程序功能并不难,但重用现有的经过验证的库总是更好。Apache-commons充满了类似的有用的东西!
如果您使用迭代器而不是 for...each 您的代码可能如下所示:
StringBuilder builder = new StringBuilder();
Iterator<Map.Entry<MyClass.Key, String>> it = data.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<MyClass.Key, String> entry = it.next();
builder.append(entry.key())
.append(": ")
.append(entry.value());
if (it.hasNext()) {
builder.append("\n");
}
}
这可能是一个更好的例子......
final StringBuilder buf = new StringBuilder();
final String separator = System.getProperty("line.separator"); // Platform new line
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
builder.append(entry.key())
.append(": ")
.append(entry.value())
.append(separator);
}
// Remove the last separator and return a string to use.
// N.b. this is likely as efficient as just using builder.toString()
// which would also copy the buffer, except we have 1 char less
// (i.e. '\n').
final String toUse = builder.substring(0, builder.length()-separator.length()-1);
这是我的简洁版本,它使用 StringBuilder 的长度属性而不是额外的变量:
StringBuilder builder = new StringBuilder();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
builder.append(builder.length() > 0 ? "\n" : "")
.append(entry.key())
.append(": ")
.append(entry.value());
}
(道歉并感谢 Jon 和 Joel 从他们的例子中“借鉴”。)
一种解决方案是为 StringBuilder 创建一个自定义包装器。它不能扩展,因此需要一个包装器。
public class CustomStringBuilder {
final String separator = System.getProperty("line.separator");
private StringBuilder builder = new StringBuilder();
public CustomStringBuilder appendLine(String str){
builder.append(str + separator);
return this;
}
public CustomStringBuilder append(String str){
builder.append(str);
return this;
}
public String toString() {
return this.builder.toString();
}
}
像这样的实现:
CustomStringBuilder builder = new CustomStringBuilder();
//iterate over as needed, but a wrapper to StringBuilder with new line features.
builder.appendLine("data goes here");
return builder.toString();
这确实有一些缺点:
我使用 StringUtils.join 解决方案来迭代集合,甚至在代码中构建轻量级构建方法模式。
假设您的 foreach 循环遍历文件,只需在每个字符串中添加一个新行,并在循环退出时删除最后一个新行。
不确定这是否是最好的,但它是更简单的方法:
循环遍历所有值并将 \n 通常附加到字符串缓冲区中。然后,做这样的事情
sb.setLength(sb.length()-1);
这就是为了补充 split 的 join 方法会派上用场的地方,因为这样您就可以使用新行作为分隔符来连接所有元素,当然它不会在结果末尾附加新行; 这就是我使用各种脚本语言(Javascript、PHP 等)的方式。
如果你使用Class Separator,你可以做
StringBuilder buf = new StringBuilder();
Separator separator = new Separator("\n");
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
builder.append(separator)
.append(entry.key())
.append(": ")
.append(entry.value());
}
分隔符在第一次使用时打印为空字符串,而分隔符在所有后续使用时打印。
哈!感谢这篇文章,我找到了另一种方法来做到这一点:
public static class Extensions
{
public static string JoinWith(this IEnumerable<string> strings, string separator)
{
return String.Join(separator, strings.ToArray());
}
}
当然这是在 C# 中,Java 将(还)不支持扩展方法,但你应该能够根据需要调整它——主要是String.Join
无论如何使用,我相信 java 有一些类似的为了那个原因。
另请注意,这意味着对字符串进行额外的迭代,因为您必须首先创建数组,然后对其进行迭代以构建字符串。此外,您将创建数组,使用其他一些方法,您可能可以使用一次仅在内存中保存一个字符串的 IEnumerable 来解决。但我真的很喜欢额外的清晰度。
当然,鉴于扩展方法功能,您也可以将任何其他代码抽象为扩展方法。
让图书馆为您做这件事。
import com.sun.deploy.util.StringUtils;
以及许多其他人都有 StringUtils,它有一个 join 方法。您可以在一行中执行此操作:
StringUtils.join(list, DELIMITER);
但对于更多上下文,这里是你如何使用哈希图来做到这一点。
public static String getDelimitatedData(HashMap<String, String> data) {
final String DELIMITER = "\n"; //Should make this a variable
ArrayList<String> entries = new ArrayList<>();
for (Map.Entry<String, String> entry : data.entrySet()) {
entries.add(entry.getKey() + ": " + entry.getValue());
}
return StringUtils.join(entries, DELIMITER);
}
使用 JDK 字符串连接 API:
String result = data.stream()
.map((k,v) -> String.format("%s : %s", k, v)
.collect(Collectors.joining("\n"));
如果您trim()
不关心空格,并且仅当您不打算在StringBuilder
.
这是一些示例代码
StringBuilder sb = new StringBuilder();
for (Map.Entry<String,String> entry : myMap.entrySet()) {
builder.append(entry.key())
.append(": ")
.append(entry.value())
.append("\n");
}
return sb.toString().trim();