Equivalentes Java de C # String.Format () e String.Join ()


Respostas:


92

O objeto Java String tem um formatmétodo (a partir de 1.5), mas nenhum joinmétodo.

Para obter vários métodos de utilitário String úteis ainda não incluídos, você pode usar org.apache.commons.lang.StringUtils .


13
coleções do google: google-collections.googlecode.com também tem um Joiner.
Ron,

10
Para sua informação, sobre o comentário de Ron, as coleções do google foram renomeadas para Guava há um tempo.
Kevin Bourrillion 01 de

3
Você deve atualizar esta resposta para refletir que o Java 8 apresenta um String.join()método.
Duncan Jones

46

String.format . Para participar, você precisa escrever o seu próprio:

 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();
 }

O texto acima vem de http://snippets.dzone.com/posts/show/91


6
Mais precisamente: StringBuffer para jdk1.4 e abaixo, StringBuilder para jdk1.5 e posteriores, já que o último não está sincronizado, portanto, um pouco mais rápido.
VonC,

2
Em vez de duas invocações iter.hasNext (), geralmente acrescento delimeter e, em seguida, "return buf.substring (0, buf.length () - delimeter.length ())".
Vilmantas Baranauskas,

2
Você pode simplificá-lo um pouco saindo mais cedo para evitar o delimitador: while (true) (add_iter; if (! Iter.hasNext ()) break; add_delim;}
13ren


29

A partir do Java 8, join()agora está disponível como dois métodos de classe na classe String. Em ambos os casos, o primeiro argumento é o delimitador.

Você pode passar CharSequences individuais como argumentos adicionais :

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

Ou você pode passar umIterable<? 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 também adiciona uma nova classe StringJoiner, que você pode usar assim:

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

Você também pode usar argumentos variáveis ​​para strings da seguinte maneira:

  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

Quanto à adesão, acredito que isso possa parecer um pouco menos complicado:

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

Não consigo usar a sintaxe Java 5 tanto quanto gostaria (acredite ou não, tenho usado 1.0.x ultimamente), então posso estar um pouco enferrujado, mas tenho certeza de que o conceito está correto .

adição de edição: acréscimos de string podem ser lentos, mas se você estiver trabalhando em código GUI ou alguma rotina de execução curta, realmente não importa se você leva 0,005 segundos ou 0,006, então se você tinha uma coleção chamada "joinMe" que você deseja anexar a uma string existente "target", não seria horrível apenas embutir isto:

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

É bastante ineficiente (e um mau hábito), mas não é nada que você seja capaz de perceber, a menos que haja milhares de strings ou que esteja dentro de um loop enorme ou que seu código seja realmente crítico para o desempenho.

Mais importante, é fácil de lembrar, curto, rápido e muito legível. O desempenho nem sempre é o vencedor automático nas escolhas de design.


O loop for está correto, mas você também deve torná-lo uma Coleção <String>. Caso contrário, você teria que dizer "for (Object o: c)", porque você não poderia garantir que tudo em c era uma String.
Michael Myers

Bom ponto, estou ainda mais enferrujado com os genéricos. Vou editá-lo em.
Bill K,

Ao concatear sequencialmente: string + string + string, o compilador usa StringBuilder para acrescentar os valores. Eu me pergunto se no método for-loop você tem o segundo lugar, se o compilador faria o mesmo.
Spencer Kormos,

@Spencer K: Ele usa um StringBuilder, mas cria um novo para cada iteração (dificilmente o método mais eficiente, mas como o compilador deveria saber?). Não sei se o compilador JIT pode otimizar isso em tempo de execução.
Michael Myers

2
Oh espere. Você está falando + =? Sim, isso é péssimo. O loop e append atualmente em minha resposta usa StringBuilder e é disso que estou falando. Embora + = tenha melhorado muito, você realmente não quer usá-lo dentro de um loop - não tanto que seja bugado, mas que pode funcionar como uma merda (Bug não é um termo geralmente usado para problemas de desempenho - pelo menos não em meus 20 anos de programação). Além disso, o JIT pode melhorar isso imensamente - mas eu não confiaria nisso.
Bill K

4

Aqui está uma resposta muito simples. Use +=uma vez que tem menos código e deixe o otimizador convertê-lo em um StringBuilderpara você. Usando esse método, você não precisa fazer nenhuma verificação "é a última" em seu loop (melhoria de desempenho) e não precisa se preocupar em remover quaisquer delimitadores no final.

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

1
Solução muito elegante, não envolvendo bibliotecas de terceiros!
Denis Itskovich

2

Eu não queria importar uma biblioteca Apache inteira para adicionar uma função de junção simples, então aqui está meu hack.

    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 O construtor de string padrão tem um método "removeCharAt (int index)" Não está aparecendo na versão que estou executando
NSjonas

@NSjonas - sim, a edição dele para minha resposta está errada. O removeCharAtnão existe e a função inteira não retorna mais uma String ... Corrigirá isso.
Martin Konecny

enquanto você está nisso ... esta solução atual lançará uma "exceção de índice fora dos limites se você passar em uma lista vazia"
NSjonas

fez uma edição para obter o comprimento correto do corte se o delim tiver mais de 1 caractere. Também foi corrigido um problema em que você estava cortando o último caractere e não o primeiro como realmente precisava
NSjonas

Obrigado pelo feedback. Atualizada.
Martin Konecny

1

Se você deseja unir (concatenar) várias strings em uma, você deve usar um StringBuilder. É muito melhor do que usar

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

Há também uma pequena vitória de desempenho sobre StringBuffer, já que StringBuilder não usa sincronização.

Para um método utilitário de propósito geral como este, ele (eventualmente) será chamado muitas vezes em muitas situações, portanto, você deve torná-lo eficiente e não alocar muitos objetos transitórios. Fizemos o perfil de muitos aplicativos Java diferentes e quase sempre descobrimos que a concatenação de string e as alocações de string / char [] ocupam uma quantidade significativa de tempo / memória.

Nossa coleção reutilizável -> método string primeiro calcula o tamanho do resultado necessário e, em seguida, cria um StringBuilder com esse tamanho inicial; isso evita duplicação / cópia desnecessária do char interno [] usado ao anexar strings.


re: pré-cálculo do tamanho: quando funciona, é ótimo. Nem sempre é possível. Lembro-me de ter lido em algum lugar que dobrar o tamanho do buffer a cada vez (ou realmente multiplicar por qualquer fator fixo) dá algo como n log n desempenho, o que não é realmente tão ruim. No caso geral, a alternativa é fazer uma lista de todas as strings que você planeja concatenar. Se você usar um ArrayList, terá de copiar novamente (a menos que você saiba o comprimento de sua sequência com antecedência) e se usar LinkedList, ele usa mais memória ram e coleta de lixo com os objetos de nó. Às vezes você não pode vencer. Tente!
Ian

Os exemplos / consultas acima presumiram alguma coleção ordenada ou matriz de Strings a serem unidas. Além disso, ao pré-calcular o tamanho, você evita caracteres extras não utilizados que o crescimento interno da matriz char [] geralmente resulta.
djb

1

Eu escrevi:

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();
}

mas Collectionnão é compatível com JSP, portanto, para a função de tag, escrevi:

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();
}

e .tldarquivado:

<?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>

e usá-lo em arquivos JSP como:

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



0

Vejo muitas implementações excessivamente complexas de String.Join aqui. Se você não tiver o Java 1.8 e não quiser importar uma nova biblioteca, a implementação abaixo deve ser suficiente.

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]" 

Então, basicamente, o String ntop armazena o valor de toda a coleção com separadores de vírgula e colchetes.


1
Não tenho certeza de que parte da pergunta isso responde? Não é um String.format a menos que você planeje adicionar os bits da string bit a bit ao array, e [1,0.92,3] não é tão versátil quanto uma string genérica .join.
Omar Kooheji de

-8

Eu usaria apenas o operador de concatenação de string "+" para juntar duas strings. s1 += s2;


Porque é uma prática ruim e lenta.
MrSnowflake
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.