C#的Java等效String.Format()和String.Join()


Answers:


92

Java String对象有一个format方法(从1.5开始),但没有join方法。

要获得一堆尚未包含的有用的String实用程序方法,可以使用org.apache.commons.lang.StringUtils


13
谷歌收藏:google-collections.googlecode.com也有一个木匠。
罗恩

10
仅供参考,罗恩(Ron)的评论在不久前更名为番石榴(google)。
凯文·布兰里恩

3
您应该更新此答案以反映Java 8引入了一种String.join()方法。
Duncan Jones

46

String.format。至于加入,您需要编写自己的:

 static String join(Collection<?> s, String delimiter) {
     StringBuilder builder = new StringBuilder();
     Iterator<?> iter = s.iterator();
     while (iter.hasNext()) {
         builder.append(iter.next());
         if (!iter.hasNext()) {
           break;                  
         }
         builder.append(delimiter);
     }
     return builder.toString();
 }

以上来自http://snippets.dzone.com/posts/show/91


6
更精确地讲:用于jdk1.4及以下版本的StringBuffer,用于jdk1.5及以下版本的StringBuilder,因为后者未同步,因此速度更快。
VonC

2
我通常不附加两次iter.hasNext()调用,而是附加delimeter,然后“返回buf.substring(0,buf.length()-delimeter.length())”。
Vilmantas Baranauskas,

2
您可以通过及早退出,以避免分隔符简化它一点点:而(真)(add_iter;如果(iter.hasNext())破; add_delim;}
13ren


29

从Java 8开始,join()现在可以作为String类的两个类方法使用。在这两种情况下,第一个参数都是定界符。

您可以将个人CharSequences作为附加参数传递

String joined = String.join(", ", "Antimony", "Arsenic", "Aluminum", "Selenium");
// "Antimony, Arsenic, Alumninum, Selenium"

或者您可以传递一个Iterable<? extends CharSequence>

List<String> strings = new LinkedList<String>();
strings.add("EX");
strings.add("TER");
strings.add("MIN");
strings.add("ATE");

String joined = String.join("-", strings);
// "EX-TER-MIN-ATE"

Java 8还添加了一个新类,StringJoiner您可以像这样使用:

StringJoiner joiner = new StringJoiner("&");
joiner.add("x=9");
joiner.add("y=5667.7");
joiner.add("z=-33.0");

String joined = joiner.toString();
// "x=9&y=5667.7&z=-33.0"


12

您还可以对字符串使用可变参数,如下所示:

  String join (String delim, String ... data) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.length; i++) {
      sb.append(data[i]);
      if (i >= data.length-1) {break;}
      sb.append(delim);
    }
    return sb.toString();
  }

4

至于join,我相信这看起来可能会简单一些:

public String join (Collection<String> c) {
    StringBuilder sb=new StringBuilder();
    for(String s: c)
        sb.append(s);
    return sb.toString();
}

我使用的Java 5语法不够用(不管信不信由你,我最近一直在使用1.0.x),所以我可能会有点生疏,但是我确信这个概念是正确的。

编辑附加:字符串追加可能会变慢,但是如果您使用的是GUI代码或某些运行时间较短的例程,那么花的时间是.005秒还是.006都没关系,因此,如果您有一个名为“ joinMe”的集合您想要附加到现有字符串“ target”上,只需内联它就不会太恐怖:

for(String s : joinMe)
    target += s;

这是非常低效的(并且是一种不良习惯),但是除非有成千上万的字符串或者这在一个巨大的循环中或者您的代码确实对性能至关重要,否则您将无法感知到任何东西。

更重要的是,它易于记忆,简短,快速且易于阅读。性能并不一定总是设计选择中的自动赢家。


for循环是正确的,但您还应使其成为Collection <String>。如果不这样做,则必须说“ for(Object o:c)”,因为您不能保证c中的所有内容都是字符串。
迈克尔·迈尔斯

好一点,我对泛型更不满意。我会在编辑它。
比尔ķ

当对内联进行字符串化:字符串+字符串+字符串时,编译器实际上使用StringBuilder附加值。我想知道在for-loop方法中您是否有第二个位置,编译器是否也会这样做。
Spencer Kormos

@Spencer K:它确实使用StringBuilder,但是它为每次迭代创建一个新的(几乎不是最有效的方法,但是编译器应该怎么知道?)。我不知道JIT编译器是否可以在运行时对其进行优化。
迈克尔·迈尔斯

2
等一下。您在说+ =吗?是的,太烂了。我的答案中当前使用的循环和追加使用StringBuilder,这就是我在说的。尽管+ =有了很大的改进,但是您真的不想在循环中使用它-与其说它有bug,不如说它有bug,但是它的性能就像胡扯(Bug不是通常用于性能问题的术语-至少不是在我20年的编程生涯中)。而且,JIT可以极大地改善这一点-但我不会依靠这一点。
比尔K

4

这是一个非常简单的答案。使用,+=因为它的代码更少,让优化器StringBuilder为您将其转换为。使用此方法,您不必在循环中进行任何“最后的检查”(提高性能),也不必担心最后会剥离任何分隔符。

        Iterator<String> iter = args.iterator();
        output += iter.hasNext() ? iter.next() : "";
        while (iter.hasNext()) {
            output += "," + iter.next();
        }

1
非常优雅的解决方案,不涉及第三方库!
Denis Itskovich 2014年

2

我不想导入整个Apache库来添加简单的join函数,所以这是我的技巧。

    public String join(String delim, List<String> destinations) {
        StringBuilder sb = new StringBuilder();
        int delimLength = delim.length();

        for (String s: destinations) {
            sb.append(s);
            sb.append(delim);
        }

        // we have appended the delimiter to the end 
        // in the previous for-loop. Let's now remove it.
        if (sb.length() >= delimLength) {
            return sb.substring(0, sb.length() - delimLength);
        } else {
            return sb.toString();
        }
    }

@MrSnowflake标准字符串生成器是否具有方法“ removeCharAt(int index)”,它没有显示在Im正在运行的版本上
NSjonas 2014年

@NSjonas-是的,他对我的答案的编辑是错误的。将removeCharAt不存在,整个函数不再返回一个字符串...会解决这个问题。
Martin Konecny

而您……目前的解决方案将引发“如果您传入空列表则索引越界异常”
NSjonas 2014年

如果delim超过1个字符,则进行编辑以修剪正确的长度。还解决了您修剪最后一个字符而不是真正需要的第一个字符的问题
NSjonas 2014年

Thx的反馈。更新。
Martin Konecny 2014年

1

如果希望将多个字符串连接(合并)为一个,则应使用StringBuilder。它比使用好得多

for(String s : joinMe)
    target += s;

由于StringBuilder不使用同步,因此在StringBuffer上还有一点性能上的优势。

对于这样的通用实用程序方法,最终(在许多情况下)将多次调用它,因此您应该使它高效,并且不要分配许多临时对象。我们已经剖析了许多许多不同的Java应用程序,并且几乎总是发现字符串连接和string / char []分配占用了大量的时间/内存。

我们可重用的collection-> string方法首先计算所需结果的大小,然后创建具有该初始大小的StringBuilder。这样可以避免在附加字符串时不必要地加倍/复制内部char []。


重新:预先计算尺寸:可行时,这很棒。并非总是可能的。我记得在某处读过,每次将缓冲区大小加倍(或实际上乘以任何固定因子)都会得到n log n的性能,这实际上并没有那么糟糕。在一般情况下,替代方法是列出要连接的所有字符串。如果使用ArrayList,则需要再次复制(除非事先知道序列的长度),如果使用LinkedList,则它将对节点对象使用更多的内存和垃圾回收。有时候你赢不了。试一试!
伊恩

上面的示例/查询假定要加入一些有序集合或字符串数​​组。此外,通过预先计算大小,可以避免内部char []数组增长通常会导致额外的未使用字符
。– djb

1

我写了自己的:

public static String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    Iterator<String> iter = col.iterator();
    if (iter.hasNext())
        sb.append(iter.next().toString());
    while (iter.hasNext()) {
        sb.append(delim);
        sb.append(iter.next().toString());
    }
    return sb.toString();
}

CollectionJSP不支持,因此对于标记功能,我写道:

public static String join(List<?> list, String delim) {
    int len = list.size();
    if (len == 0)
        return "";
    StringBuilder sb = new StringBuilder(list.get(0).toString());
    for (int i = 1; i < len; i++) {
        sb.append(delim);
        sb.append(list.get(i).toString());
    }
    return sb.toString();
}

.tld存档:

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
    <function>
        <name>join</name>
        <function-class>com.core.util.ReportUtil</function-class>
        <function-signature>java.lang.String join(java.util.List, java.lang.String)</function-signature>
    </function>
</taglib>

并在JSP文件中将其用作:

<%@taglib prefix="funnyFmt" uri="tag:com.core.util,2013:funnyFmt"%>
${funnyFmt:join(books, ", ")}



0

我在这里看到了String.Join的许多过于复杂的实现。如果您没有Java 1.8,并且不想导入新的库,则下面的实现就足够了。

public String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    for ( String s : col ) {
        if ( sb.length() != 0 ) sb.append(delim);
        sb.append(s);
    }
    return sb.toString();
}

-1
ArrayList<Double> j=new ArrayList<>; 
j.add(1);
j.add(.92);
j.add(3); 
String ntop=j.toString(); //ntop= "[1, 0.92, 3]" 

因此,基本上,String ntop用逗号分隔符和方括号存储整个集合的值。


1
我不确定这将回答问题的哪一部分?它不是String.format,除非您计划将字符串的位一点一点地添加到数组中,并且[1,0.92,3]不如通用字符串.join通用。
Omar Kooheji 2013年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.