自定义 TreeSet 打印 Map.Entry 值的方式
Customize the way TreeSet prints Map.Entry values
我有一个 TreeSet
包含 Map.Entry<String, Double>
值,当我尝试使用 Iterator
迭代这个结构并打印它的键值对时,标准输出是看起来像的东西:
Tolkien=40.25 JKRowling=35.5 OBowden=14.0
但是我想为我的输出使用 自定义格式 并将 =
符号替换为 ->
,例如:
Tolkien -> 40.25, JKRowling -> 35.5, OBowden -> 14.0
这是我现在的代码:
Iterator iterator;.
iterator = lib.getSortedBooks().iterator();
while (iterator.hasNext()) {
System.out.printf(iterator.next() + " ");
}
正确设置输出格式的最佳方法是什么?
System.out
中的打印方法在内部使用 toString()
,因此当您调用 toString()
时,您得到的结果与您在输出中看到的相同。然后用箭头替换那个等号。
System.out.printf(iterator.next().toString().replace("=", " -> ") + " ");
一个更优雅的方法(实际上是正确的方法,因为 Map.Entry
没有承诺 toString()
格式):
Map.Entry<K, V> entry = iterator.next();
System.out.printf(entry.getKey() + " -> " + entry.getValue() + " ");
您只需将 =
字符替换为 ->
字符即可解决您的问题,例如:
Iterator<Entry<String, Double>> iterator = lib.getSortedBooks().iterator();
while (iterator.hasNext()) {
Entry book = iterator.next();
String bookAsText = book.toString();
String adjustedText = bookAsText.replace("=", " -> ");
System.out.print(adjustedText + ", ");
}
请注意,您的输出现在最后有一个尾随 ,
。您可以使用 String#substring
方法删除它,或者如果您正在处理最后一个元素(使用 iterator.hasNext()
向前看一个元素)则不附加它,或者只使用 StringJoiner
我'一会儿给你看。
但是,如果您总是想要显式输出,那么您应该不依赖 toString
方法打印它确实如此。这可能会在未来改变,谁知道呢。
您应该明确地构建输出。 StringJoiner class 对此很有帮助,它允许您通过添加分隔符(如 ,
)来连接字符串。因此使用这样的代码:
Set<Entry<String, Double>> books = lib.getSortedBooks();
String entryDelimiter = ", "
String valueDelimiter = " -> ";
StringJoiner sj = new StringJoiner(entryDelimiter);
for (Entry<String, Double> book : books) {
sj.add(book.getKey());
sj.add(valueDelimiter);
sj.add(book.getValue());
}
String output = sj.toString();
System.out.println(output);
或更紧凑的Java 8解决方案使用Streams
:
String output = lib.getSortedBooks().stream()
.map(book -> book.getKey() + " -> " + book.getValue())
.collect(Collectors.joining(", "));
System.out.println(output);
该方法使用集合作为流的源。然后它首先将每个元素转移到 book.getKey() + "->" + book.getValue()
中,这就是 Stream#map
所做的。之后它将所有这些元素与 ,
连接起来并最终收集它们。
请注意,如果元素不再排序对您来说没问题,它也可以并行化。因此只需在两者之间调用 Stream#parallel
。它可以将给定的流“转换”为并行流。
根据项目的大小,您应该考虑将书籍的表示形式从 Map.Entry
更改为自己的 class Book
,例如:
public class Book() {
private final String mAuthor;
private final double mPrice;
public Book(final String author, final double price) {
this.mAuthor = author;
this.mPrice = price;
}
public String getAuthor() {
return this.mAuthor;
}
public double getPrice() {
return this.mPrice;
}
@Override
public String toString() {
return getAuthor + " -> " + getPrice();
}
}
此方法对于将来的更改更加灵活,并且还允许您添加您认为最合适的 toString
表示。
因为那么,假设 lib.getSortedBooks()
returns 一组 Book
而不是 Map.Entry
,你可以简单地做:
String output = lib.getSortedBooks().stream()
.map(Book::toString)
.collect(Collectors.joining(", "));
我有一个 TreeSet
包含 Map.Entry<String, Double>
值,当我尝试使用 Iterator
迭代这个结构并打印它的键值对时,标准输出是看起来像的东西:
Tolkien=40.25 JKRowling=35.5 OBowden=14.0
但是我想为我的输出使用 自定义格式 并将 =
符号替换为 ->
,例如:
Tolkien -> 40.25, JKRowling -> 35.5, OBowden -> 14.0
这是我现在的代码:
Iterator iterator;.
iterator = lib.getSortedBooks().iterator();
while (iterator.hasNext()) {
System.out.printf(iterator.next() + " ");
}
正确设置输出格式的最佳方法是什么?
System.out
中的打印方法在内部使用 toString()
,因此当您调用 toString()
时,您得到的结果与您在输出中看到的相同。然后用箭头替换那个等号。
System.out.printf(iterator.next().toString().replace("=", " -> ") + " ");
一个更优雅的方法(实际上是正确的方法,因为 Map.Entry
没有承诺 toString()
格式):
Map.Entry<K, V> entry = iterator.next();
System.out.printf(entry.getKey() + " -> " + entry.getValue() + " ");
您只需将 =
字符替换为 ->
字符即可解决您的问题,例如:
Iterator<Entry<String, Double>> iterator = lib.getSortedBooks().iterator();
while (iterator.hasNext()) {
Entry book = iterator.next();
String bookAsText = book.toString();
String adjustedText = bookAsText.replace("=", " -> ");
System.out.print(adjustedText + ", ");
}
请注意,您的输出现在最后有一个尾随 ,
。您可以使用 String#substring
方法删除它,或者如果您正在处理最后一个元素(使用 iterator.hasNext()
向前看一个元素)则不附加它,或者只使用 StringJoiner
我'一会儿给你看。
但是,如果您总是想要显式输出,那么您应该不依赖 toString
方法打印它确实如此。这可能会在未来改变,谁知道呢。
您应该明确地构建输出。 StringJoiner class 对此很有帮助,它允许您通过添加分隔符(如 ,
)来连接字符串。因此使用这样的代码:
Set<Entry<String, Double>> books = lib.getSortedBooks();
String entryDelimiter = ", "
String valueDelimiter = " -> ";
StringJoiner sj = new StringJoiner(entryDelimiter);
for (Entry<String, Double> book : books) {
sj.add(book.getKey());
sj.add(valueDelimiter);
sj.add(book.getValue());
}
String output = sj.toString();
System.out.println(output);
或更紧凑的Java 8解决方案使用Streams
:
String output = lib.getSortedBooks().stream()
.map(book -> book.getKey() + " -> " + book.getValue())
.collect(Collectors.joining(", "));
System.out.println(output);
该方法使用集合作为流的源。然后它首先将每个元素转移到 book.getKey() + "->" + book.getValue()
中,这就是 Stream#map
所做的。之后它将所有这些元素与 ,
连接起来并最终收集它们。
请注意,如果元素不再排序对您来说没问题,它也可以并行化。因此只需在两者之间调用 Stream#parallel
。它可以将给定的流“转换”为并行流。
根据项目的大小,您应该考虑将书籍的表示形式从 Map.Entry
更改为自己的 class Book
,例如:
public class Book() {
private final String mAuthor;
private final double mPrice;
public Book(final String author, final double price) {
this.mAuthor = author;
this.mPrice = price;
}
public String getAuthor() {
return this.mAuthor;
}
public double getPrice() {
return this.mPrice;
}
@Override
public String toString() {
return getAuthor + " -> " + getPrice();
}
}
此方法对于将来的更改更加灵活,并且还允许您添加您认为最合适的 toString
表示。
因为那么,假设 lib.getSortedBooks()
returns 一组 Book
而不是 Map.Entry
,你可以简单地做:
String output = lib.getSortedBooks().stream()
.map(Book::toString)
.collect(Collectors.joining(", "));