Maneira simples de repetir um String em java

Eu estou procurando um método simples ou operador comum que me permite repetir algumas String n vezes. Eu sei que eu poderia escrever isso usando um loop for, mas eu gostaria de evitar loops sempre que necessário e um método direto simples deveria existir em algum lugar.

String str = "abc"; String repeated = str.repeat(3); repeated.equals("abcabcabc"); 

Relacionado a:

repeat string javascript Cria NSString repetindo outra string um determinado número de vezes

Editado

Eu tento evitar loops quando eles não são completamente necessários porque:

  1. Eles adicionam ao número de linhas de código, mesmo que estejam escondidos em outra function.

  2. Alguém lendo meu código tem que descobrir o que estou fazendo nesse loop. Mesmo que seja comentado e tenha nomes significativos de variables, eles ainda precisam ter certeza de que não estão fazendo nada “inteligente”.

  3. Os programadores adoram colocar as coisas espertas em loops, mesmo que eu escreva para “fazer apenas o que se pretende fazer”, isso não impede que alguém apareça e acrescente mais algumas “correções” inteligentes.

  4. Eles são muitas vezes fáceis de errar. For loops envolvendo índices tendem a gerar um erro.

  5. For loops geralmente reutilizam as mesmas variables, aumentando a chance de realmente encontrar bugs.

  6. For loops aumentam o número de lugares que um caçador de bugs tem que procurar.

Do Java 11 em diante, há um método String::repeat que faz exatamente o que você pediu:

 String str = "abc"; String repeated = str.repeat(3); repeated.equals("abcabcabc"); 

Seu Javadoc diz:

 /** * Returns a string whose value is the concatenation of this * string repeated {@code count} times. * 

* If this string is empty or count is zero then the empty * string is returned. * * @param count number of times to repeat * * @return A string composed of this string repeated * {@code count} times or the empty string if this * string is empty or count is zero * * @throws IllegalArgumentException if the {@code count} is * negative. * * @since 11 */

Aqui está a versão mais curta (requer Java 1.5+):

 repeated = new String(new char[n]).replace("\0", s); 

Onde n é o número de vezes que você deseja repetir a string e s é a string a ser repetida.

Nenhuma importação ou biblioteca necessária.

Comum Lang StringUtils.repeat ()

Uso:

 String str = "abc"; String repeated = StringUtils.repeat(str, 3); repeated.equals("abcabcabc"); 

No Java 8 e acima, há uma maneira fácil:

 // create a string made up of n copies of string s String.join("", Collections.nCopies(n, s)); 

Caso contrário, isso é tão simples quanto parece:

 // create a string made up of n copies of string s String.format("%0" + n + "d", 0).replace("0",s); 

O String.join do Java 8 fornece uma maneira de fazer isso em conjunto com o Collections.nCopies :

 // say hello 100 times System.out.println(String.join("", Collections.nCopies(100, "hello"))); 

Aqui está uma maneira de fazer isso usando apenas funções padrão de String e sem loops explícitos:

 // create a string made up of n copies of s repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s); 

Se você é como eu e quer usar o Google Goiaba e não o Apache Commons. Você pode usar o método repeat na class Guava Strings.

 Strings.repeat("-", 60); 

Com o java-8 , você também pode usar o Stream.generate .

 import static java.util.stream.Collectors.joining; ... String repeated = Stream.generate(() -> "abc").limit(3).collect(joining()); //"abcabcabc" 

e você pode envolvê-lo em um método utilitário simples, se necessário:

 public static String repeat(String str, int times) { return Stream.generate(() -> str).limit(times).collect(joining()); } 

Então você quer evitar loops?

Aqui você tem:

 public static String repeat(String s, int times) { if (times < = 0) return ""; else return s + repeat(s, times-1); } 

(claro que eu sei que isso é feio e ineficiente, mas não tem loops :-p)

Você quer mais simples e mais bonita? use jython:

 s * 3 

Edit : vamos otimizá-lo um pouco 😀

 public static String repeat(String s, int times) { if (times < = 0) return ""; else if (times % 2 == 0) return repeat(s+s, times/2); else return s + repeat(s+s, times/2); } 

Edit2 : Eu fiz um benchmark rápido e sujo para as 4 principais alternativas, mas eu não tenho tempo para executá-lo várias vezes para obter os meios e traçar os tempos para várias inputs ... Então aqui está o código se alguém quiser experimentá-lo:

 public class Repeat { public static void main(String[] args) { int n = Integer.parseInt(args[0]); String s = args[1]; int l = s.length(); long start, end; start = System.currentTimeMillis(); for (int i = 0; i < n; i++) { if(repeatLog2(s,i).length()!=i*l) throw new RuntimeException(); } end = System.currentTimeMillis(); System.out.println("RecLog2Concat: " + (end-start) + "ms"); start = System.currentTimeMillis(); for (int i = 0; i < n; i++) { if(repeatR(s,i).length()!=i*l) throw new RuntimeException(); } end = System.currentTimeMillis(); System.out.println("RecLinConcat: " + (end-start) + "ms"); start = System.currentTimeMillis(); for (int i = 0; i < n; i++) { if(repeatIc(s,i).length()!=i*l) throw new RuntimeException(); } end = System.currentTimeMillis(); System.out.println("IterConcat: " + (end-start) + "ms"); start = System.currentTimeMillis(); for (int i = 0; i < n; i++) { if(repeatSb(s,i).length()!=i*l) throw new RuntimeException(); } end = System.currentTimeMillis(); System.out.println("IterStrB: " + (end-start) + "ms"); } public static String repeatLog2(String s, int times) { if (times <= 0) { return ""; } else if (times % 2 == 0) { return repeatLog2(s+s, times/2); } else { return s + repeatLog2(s+s, times/2); } } public static String repeatR(String s, int times) { if (times <= 0) { return ""; } else { return s + repeatR(s, times-1); } } public static String repeatIc(String s, int times) { String tmp = ""; for (int i = 0; i < times; i++) { tmp += s; } return tmp; } public static String repeatSb(String s, int n) { final StringBuilder sb = new StringBuilder(); for(int i = 0; i < n; i++) { sb.append(s); } return sb.toString(); } } 

São necessários dois argumentos, o primeiro é o número de iterações (cada function é executada com arg de tempos de repetição de 1..n) e a segunda é a cadeia a ser repetida.

Até agora, uma rápida inspeção dos tempos em execução com diferentes insumos deixa o ranking mais ou menos assim:

  1. Iterativo StringBuilder anexado (1x).
  2. Invocações log2 de concatenação recursiva (~ 3x).
  3. Invocações lineares de concatenação recursiva (~ 30x).
  4. Concatenação iterativa linear (~ 45x).

Eu nunca imaginei que a function recursiva fosse mais rápida que o loop for : -o

Divirta-se (ctional xD).

Isso contém menos caracteres do que sua pergunta

 public static String repeat(String s, int n) { if(s == null) { return null; } final StringBuilder sb = new StringBuilder(s.length() * n); for(int i = 0; i < n; i++) { sb.append(s); } return sb.toString(); } 

com base na resposta do fortran , esta é uma versão que usa um StringBuilder:

 public static void repeat(StringBuilder stringBuilder, String s, int times) { if (times > 0) { repeat(stringBuilder.append(s), s, times - 1); } } public static String repeat(String s, int times) { StringBuilder stringBuilder = new StringBuilder(s.length() * times); repeat(stringBuilder, s, times); return stringBuilder.toString(); } 

usar o dólar é simples como digitar:

 @Test public void repeatString() { String string = "abc"; assertThat($(string).repeat(3).toString(), is("abcabcabc")); } 

PS: repetir funciona também para matriz, lista, conjunto, etc

Eu queria que uma function criasse uma lista delimitada por vírgulas de pontos de interrogação para propósitos do JDBC e encontrasse este post. Então, decidi pegar duas variantes e ver qual delas tinha melhor desempenho. Após 1 milhão de iterações, o StringBuilder variou 2 segundos (fun1), e a versão cripicamente mais ótima (fun2) levou 30 segundos. Qual é o ponto de ser enigmático novamente?

 private static String fun1(int size) { StringBuilder sb = new StringBuilder(size * 2); for (int i = 0; i < size; i++) { sb.append(",?"); } return sb.substring(1); } private static String fun2(int size) { return new String(new char[size]).replaceAll("\0", ",?").substring(1); } 

usando apenas classs JRE ( System.arraycopy ) e tentando minimizar o número de objects temporários, você pode escrever algo como:

 public static String repeat(String toRepeat, int times) { if (toRepeat == null) { toRepeat = ""; } if (times < 0) { times = 0; } final int length = toRepeat.length(); final int total = length * times; final char[] src = toRepeat.toCharArray(); char[] dst = new char[total]; for (int i = 0; i < total; i += length) { System.arraycopy(src, 0, dst, i, length); } return String.copyValueOf(dst); } 

EDITAR

e sem loops você pode tentar:

 public static String repeat2(String toRepeat, int times) { if (toRepeat == null) { toRepeat = ""; } if (times < 0) { times = 0; } String[] copies = new String[times]; Arrays.fill(copies, toRepeat); return Arrays.toString(copies). replace("[", ""). replace("]", ""). replaceAll(", ", ""); } 

EDIT 2

usar Coleções é ainda menor:

 public static String repeat3(String toRepeat, int times) { return Collections.nCopies(times, toRepeat). toString(). replace("[", ""). replace("]", ""). replaceAll(", ", ""); } 

no entanto, eu ainda gosto da primeira versão.

Solução OOP

Quase todas as respostas propõem uma function estática como solução, mas pensando em Orientado a Objetos (para propósitos de reutilização e clareza) eu criei uma Solução via Delegação através da CharSequence-Interface (que também abre a usabilidade em CharSequence-Classes mutáveis).

A seguinte class pode ser usada com ou sem Separator-String / CharSequence e cada chamada para “toString ()” constrói a String repetida final. O Input / Separator não está limitado apenas a String-Class, mas pode ser de qualquer class que implemente CharSequence (por exemplo, StringBuilder, StringBuffer, etc)!

Código fonte:

 /** * Helper-Class for Repeating Strings and other CharSequence-Implementations * @author Maciej Schuttkowski */ public class RepeatingCharSequence implements CharSequence { final int count; CharSequence internalCharSeq = ""; CharSequence separator = ""; /** * CONSTRUCTOR - RepeatingCharSequence * @param input CharSequence to repeat * @param count Repeat-Count */ public RepeatingCharSequence(CharSequence input, int count) { if(count < 0) throw new IllegalArgumentException("Can not repeat String \""+input+"\" less than 0 times! count="+count); if(count > 0) internalCharSeq = input; this.count = count; } /** * CONSTRUCTOR - Strings.RepeatingCharSequence * @param input CharSequence to repeat * @param count Repeat-Count * @param separator Separator-Sequence to use */ public RepeatingCharSequence(CharSequence input, int count, CharSequence separator) { this(input, count); this.separator = separator; } @Override public CharSequence subSequence(int start, int end) { checkBounds(start); checkBounds(end); int subLen = end - start; if (subLen < 0) { throw new IndexOutOfBoundsException("Illegal subSequence-Length: "+subLen); } return (start == 0 && end == length()) ? this : toString().substring(start, subLen); } @Override public int length() { //We return the total length of our CharSequences with the separator 1 time less than amount of repeats: return count < 1 ? 0 : ( (internalCharSeq.length()*count) + (separator.length()*(count-1))); } @Override public char charAt(int index) { final int internalIndex = internalIndex(index); //Delegate to Separator-CharSequence or Input-CharSequence depending on internal index: if(internalIndex > internalCharSeq.length()-1) { return separator.charAt(internalIndex-internalCharSeq.length()); } return internalCharSeq.charAt(internalIndex); } @Override public String toString() { return count < 1 ? "" : new StringBuilder(this).toString(); } private void checkBounds(int index) { if(index < 0 || index >= length()) throw new IndexOutOfBoundsException("Index out of Bounds: "+index); } private int internalIndex(int index) { // We need to add 1 Separator-Length to total length before dividing, // as we subtracted one Separator-Length in "length()" return index % ((length()+separator.length())/count); } } 

Exemplo de uso:

 public static void main(String[] args) { //String input = "12345"; //StringBuffer input = new StringBuffer("12345"); StringBuilder input = new StringBuilder("123"); //String separator = "< =>"; StringBuilder separator = new StringBuilder("< =");//.append('>'); int repeatCount = 2; CharSequence repSeq = new RepeatingCharSequence(input, repeatCount, separator); String repStr = repSeq.toString(); System.out.println("Repeat="+repeatCount+"\tSeparator="+separator+"\tInput="+input+"\tLength="+input.length()); System.out.println("CharSeq:\tLength="+repSeq.length()+"\tVal="+repSeq); System.out.println("String :\tLength="+repStr.length()+"\tVal="+repStr); //Here comes the Magic with a StringBuilder as Input, as you can append to the String-Builder //and at the same Time your Repeating-Sequence's toString()-Method returns the updated String :) input.append("ff"); System.out.println(repSeq); //Same can be done with the Separator: separator.append("===").append('>'); System.out.println(repSeq); } 

Exemplo de saída:

 Repeat=2 Separator=< = Input=123 Length=3 CharSeq: Length=8 Val=123<=123 String : Length=8 Val=123<=123 123ff<=123ff 123ff<====>123ff 

Se a velocidade é sua preocupação, você deve usar menos cópias de memory possível. Assim, é necessário trabalhar com matrizes de caracteres.

 public static String repeatString(String what, int howmany) { char[] pattern = what.toCharArray(); char[] res = new char[howmany * pattern.length]; int length = pattern.length; for (int i = 0; i < howmany; i++) System.arraycopy(pattern, 0, res, i * length, length); return new String(res); } 

Para testar a velocidade, um método otimizado semelhante usando o StirngBuilder é assim:

 public static String repeatStringSB(String what, int howmany) { StringBuilder out = new StringBuilder(what.length() * howmany); for (int i = 0; i < howmany; i++) out.append(what); return out.toString(); } 

e o código para testá-lo:

 public static void main(String... args) { String res; long time; for (int j = 0; j < 1000; j++) { res = repeatString("123", 100000); res = repeatStringSB("123", 100000); } time = System.nanoTime(); res = repeatString("123", 1000000); time = System.nanoTime() - time; System.out.println("elapsed repeatString: " + time); time = System.nanoTime(); res = repeatStringSB("123", 1000000); time = System.nanoTime() - time; System.out.println("elapsed repeatStringSB: " + time); } 

E aqui a corrida resulta do meu sistema:

 elapsed repeatString: 6006571 elapsed repeatStringSB: 9064937 

Note que o teste de loop é para chutar no JIT e ter ótimos resultados.

Se você está preocupado com o desempenho, apenas use um StringBuilder dentro do loop e faça um .toString () na saída do Loop. Heck, escreva sua própria class Util e reutilize-a. 5 linhas de código máx.

Eu realmente gosto dessa pergunta. Há muito conhecimento e estilos. Então eu não posso sair sem mostrar meu rock and roll;)

 { String string = repeat("1234567890", 4); System.out.println(string); System.out.println("======="); repeatWithoutCopySample(string, 100000); System.out.println(string);// This take time, try it without printing System.out.println(string.length()); } /** * The core of the task. */ @SuppressWarnings("AssignmentToMethodParameter") public static char[] repeat(char[] sample, int times) { char[] r = new char[sample.length * times]; while (--times > -1) { System.arraycopy(sample, 0, r, times * sample.length, sample.length); } return r; } /** * Java classic style. */ public static String repeat(String sample, int times) { return new String(repeat(sample.toCharArray(), times)); } /** * Java extreme memory style. */ @SuppressWarnings("UseSpecificCatch") public static void repeatWithoutCopySample(String sample, int times) { try { Field valueStringField = String.class.getDeclaredField("value"); valueStringField.setAccessible(true); valueStringField.set(sample, repeat((char[]) valueStringField.get(sample), times)); } catch (Exception ex) { throw new RuntimeException(ex); } } 

Você gosta disso?

Laço simples

 public static String repeat(String string, int times) { StringBuilder out = new StringBuilder(); while (times-- > 0) { out.append(string); } return out.toString(); } 

Usando a recursion, você pode fazer o seguinte (usando operadores ternários, uma linha máxima):

 public static final String repeat(String string, long number) { return number == 1 ? string : (number % 2 == 0 ? repeat(string + string, number / 2) : string + repeat(string + string, (number - 1) / 2)); } 

Eu sei, é feio e provavelmente não é eficiente, mas é uma linha!

por uma questão de legibilidade e portabilidade:

 public String repeat(String str, int count){ if(count < = 0) {return "";} return new String(new char[count]).replace("\0", str); } 

Apesar do seu desejo de não usar loops, acho que você deveria usar um loop.

 String repeatString(String s, int repetitions) { if(repetitions < 0) throw SomeException(); else if(s == null) return null; StringBuilder stringBuilder = new StringBuilder(s.length() * repetitions); for(int i = 0; i < repetitions; i++) stringBuilder.append(s); return stringBuilder.toString(); } 

Suas razões para não usar um loop for não são boas. Em resposta às suas críticas:

  1. Seja qual for a solução que você usa, quase certamente será mais longa do que isso. O uso de uma function pré-construída somente o coloca sob mais capas.
  2. Alguém que lê o seu código terá que descobrir o que você está fazendo nesse loop. Dado que um for-loop é a maneira idiomática de fazer isso, seria muito mais fácil descobrir se você fez isso com um loop for.
  3. Sim, alguém pode adicionar algo inteligente, mas evitando um loop for você está fazendo algo inteligente . É como atirar no pé intencionalmente para evitar atirar no pé por acidente.
  4. Erros off-one também são fáceis de entender com um único teste. Como você deve testar seu código, um erro off-by-one deve ser fácil de corrigir e capturar. E vale a pena notar: o código acima não contém um erro off-by-one. For loops são igualmente fáceis de acertar.
  5. Portanto, não reutilize variables. Isso não é culpa do loop for.
  6. Mais uma vez, o mesmo acontece com qualquer solução que você usa. E como eu observei antes; um caçador de bugs provavelmente estará esperando que você faça isso com um loop for, assim eles terão mais facilidade em encontrá-lo se você usar um loop for.
 public static String repeat(String str, int times) { int length = str.length(); int size = length * times; char[] c = new char[size]; for (int i = 0; i < size; i++) { c[i] = str.charAt(i % length); } return new String(c); } 

Tente isso:

 public static char[] myABCs = {'a', 'b', 'c'}; public static int numInput; static Scanner in = new Scanner(System.in); public static void main(String[] args) { System.out.print("Enter Number of Times to repeat: "); numInput = in.nextInt(); repeatArray(numInput); } public static int repeatArray(int y) { for (int a = 0; a < y; a++) { for (int b = 0; b < myABCs.length; b++) { System.out.print(myABCs[b]); } System.out.print(" "); } return y; } 

Not the shortest, but (i think) the fastest way is to use the StringBuilder:

  /** * Repeat a String as many times you need. * * @param i - Number of Repeating the String. * @param s - The String wich you want repeated. * @return The string n - times. */ public static String repeate(int i, String s) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < i; j++) sb.append(s); return sb.toString(); } 

here is the latest Stringutils.java StringUtils.java

  public static String repeat(String str, int repeat) { // Performance tuned for 2.0 (JDK1.4) if (str == null) { return null; } if (repeat < = 0) { return EMPTY; } int inputLength = str.length(); if (repeat == 1 || inputLength == 0) { return str; } if (inputLength == 1 && repeat <= PAD_LIMIT) { return repeat(str.charAt(0), repeat); } int outputLength = inputLength * repeat; switch (inputLength) { case 1 : return repeat(str.charAt(0), repeat); case 2 : char ch0 = str.charAt(0); char ch1 = str.charAt(1); char[] output2 = new char[outputLength]; for (int i = repeat * 2 - 2; i >= 0; i--, i--) { output2[i] = ch0; output2[i + 1] = ch1; } return new String(output2); default : StringBuilder buf = new StringBuilder(outputLength); for (int i = 0; i < repeat; i++) { buf.append(str); } return buf.toString(); } } 

it doesn't even need to be this big, can be made into this, and can be copied and pasted into a utility class in your project.

  public static String repeat(String str, int num) { int len = num * str.length(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < times; i++) { sb.append(str); } return sb.toString(); } 

So e5, I think the best way to do this would be to simply use the above mentioned code,or any of the answers here. but commons lang is just too big if it's a small project

I created a recursive method that do the same thing you want.. feel free to use this…

 public String repeat(String str, int count) { return count > 0 ? repeat(str, count -1) + str: ""; } 

i have the same answer on Can I multiply strings in java to repeat sequences?

 repeated = str + str + str; 

Sometimes simple is best. Everyone reading the code can see what’s happening.

And the compiler will do the fancy stuff with StringBuilder behind the scenes for you.

Here is a simple way to repeat a star a number of times (up to some known maximum):

 String stars = "*****".substring(0, n);