815

I'm looking for a simple commons method or operator that allows me to repeat some string n times. I know I could write this using a for loop, but I wish to avoid for loops whenever necessary and a simple direct method should exist somewhere.

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

repeated.equals("abcabcabc");

Related to:

repeat string javascript Create NSString by repeating another string a given number of times

Edited

I try to avoid for loops when they are not completely necessary because:

  1. They add to the number of lines of code even if they are tucked away in another function.

  2. Someone reading my code has to figure out what I am doing in that for loop. Even if it is commented and has meaningful variables names, they still have to make sure it is not doing anything "clever".

  3. Programmers love to put clever things in for loops, even if I write it to "only do what it is intended to do", that does not preclude someone coming along and adding some additional clever "fix".

  4. They are very often easy to get wrong. For loops involving indexes tend to generate off by one bugs.

  5. For loops often reuse the same variables, increasing the chance of really hard to find scoping bugs.

  6. For loops increase the number of places a bug hunter has to look.

18
  • 49
    I understand that for loops can cause some real issues. But you shouldn't try to avoid for loops "at all costs" because if it costs you readability, maintainability, and speed, you're being counterproductive. This is one of those cases. Commented Aug 5, 2009 at 21:39
  • 10
    "They add to the number of lines of code even if they are tucked away in another function"...wow, just wow. Big-O, not LoC Commented Aug 5, 2009 at 23:40
  • 9
    @imagist I'm avoiding for loops in situations where it costs me readability, and maintainability. I consider speed as the least important issue here (a non-issue in fact). I think for loops are overused and I am trying to learn to only use for loops when they are necessary and not as a default solution. Commented Aug 6, 2009 at 0:29
  • 4
    @Pyrolistical I'm not claiming performance or asymptotic benefits. Rather saying that by writing less code, and using library functions rather than reinventing the wheel I reduce the bug surface area(Lines of Code) while increasing readability. Both good things I'm sure you'll agree. Commented Aug 6, 2009 at 0:51
  • 4
    @e5;sorry for posting years later.I find this question so appropriate. If inserted in a method, arguments should be tested (times>=0), errors thrown etc.This adds robustness but also lines of code to read. Repeating a string is something unambiguous.Who reads the code knows exactly what a string.repeat does, even without a line of comment or javadoc.If we use a stable library, is reasonable to think that a so-simple function has no bugs,YET introduces some form of "robustness" check that we even need to worry about.If i could ask 10 improvements, this (kind of) things would be one. Commented Sep 21, 2011 at 21:01

33 Answers 33

1026

Here is the shortest version (Java 1.5+ required):

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

Where n is the number of times you want to repeat the string and s is the string to repeat.

No imports or libraries needed.

Sign up to request clarification or add additional context in comments.

13 Comments

I don't think it's obfuscated at all. Primitive types (char[], in this case) are instantiated with nulls, then a String is created from the char[], and the nulls are replaced() with the character you want in s
While this is very clever (+1) I think it pretty much proves the point that for loops often make for clearer code
To those who complain about obfuscation, readability depends on literacy. This is perfectly clear in what it does and educational for those who may not see it right away. This is what you get with Java by the way.
This should really be marked as the answer. When your looking for a 'simple' solution, including external libraries should really be a last resort if a better alternative exists. And this is a very very good alternative.
@user686249: There are only replace(char oldChar, char newChar) and replace(CharSequence target, CharSequence replacement) so I don't see how that could work
|
604

If you are using Java <= 7, this is as "concise" as it gets:

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

In Java 8 and above there is a more readable way:

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

Finally, for Java 11 and above, there is a new repeat​(int count) method specifically for this purpose(link)

"abc".repeat(12);

Alternatively, if your project uses java libraries there are more options.

For Apache Commons:

StringUtils.repeat("abc", 12);

For Google Guava:

Strings.repeat("abc", 12);

2 Comments

The former causes an exception when n is zero.
For anyone curious, the new "blah".repeat(10) in >=Java 11 appears to be very efficient, allocating byte arrays directly much like StringBuilder. Probably the best way to repeat strings from here on out!
422
+100

String::repeat

". ".repeat(7)  // Seven period-with-space pairs: . . . . . . . 

New in Java 11 is the method String::repeat that does exactly what you asked for:

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

Its Javadoc says:

/**
 * Returns a string whose value is the concatenation of this
 * string repeated {@code count} times.
 * <p>
 * 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
 */ 

2 Comments

@Nicolai source code for it, just in case someone cares hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/…
Probably obvious, but you can call this method on a string literal too: "abc".repeat(3)
326

Commons Lang StringUtils.repeat()

Usage:

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

repeated.equals("abcabcabc");

14 Comments

using a one-method-dependency for the simplicity's sake in the long run can resulting in a jar-hell
Sure, except it's commons lang. I don't think I've ever seen a project over 5000 LOCS that didn't have commons lang.
Commons Lang is open source - download it and take a look. Of course it has a loop inside, but it's not quite as simple. A lot of effort went into profiling and optimizing that implementation.
I don't avoid loops for performance reason (read my reasons in the question). When someone sees StringUtils.repeat, they know what I am doing. They don't have to worry that I attempted to write my own version of repeat and made a mistake. It is an atomic cognitive unit!
@Thorbjørn Ravn Andersen - it can get a LOT more interesting if things keep being taken out of context
|
152

Java 8's String.join provides a tidy way to do this in conjunction with Collections.nCopies:

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

4 Comments

thank you! For android TextUtils.join() can be used instead of String.join()
Thank you for this answer. It's seems to be the cleanest way without using any external API oder utility method! very good!!
The nice thing about this method is that with join you can provide a separator character which works out to be very handy if you are, say, building up a CSV list. With all the other methods you have a terminating joining character that needs to be stripped out in a separate operation.
this is a nice readable answer, but just for context (from a naive benchmark) it's 3-4x slower than just a for loop over a StringBuilder, i.e., StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) { sb.append("hello"); } return sb.toString();
105

Here's a way to do it using only standard String functions and no explicit loops:

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

6 Comments

Amazing :-) Although beware of n becoming zero…!
I think he meant replaceAll
@Vijay Dev & fortran: No, he meant replace(). In Java 1.5+, there is an overloaded version of replace() that takes two CharSequences (which include Strings): download.oracle.com/javase/1.5.0/docs/api/java/lang/…
@mzuba let's say n=3: it first formats a string to look something like %03d (%% is to escape the percentage sign), which is the formatting code to add 3 padding zeroes, then formats 0 with that, leading to 000, and finally replaces each 0 with the strings
You can make the solution less ugly and easier to understand: String.format("%0"+n+"d", 0).replace("0", s)
|
88

If you're like me and want to use Google Guava and not Apache Commons. You can use the repeat method in the Guava Strings class.

Strings.repeat("-", 60);

2 Comments

... and get 3Mb of new dependencies.
@MonoThreaded I thought it would go without saying, but don't include guava just to do a string repeat. My answer was about if you're already using guava anyway then this is how you'd do it.
55

With , you can also use Stream.generate.

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

and you can wrap it in a simple utility method if needed:

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

1 Comment

... or return IntStream.range(0, times).mapToObj(i -> str).collect(joining()); which parallelizes better
33

So you want to avoid loops?

Here you have it:

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

(of course I know this is ugly and inefficient, but it doesn't have loops :-p)

You want it simpler and prettier? use jython:

s * 3

Edit: let's optimize it a little bit :-D

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: I've done a quick and dirty benchmark for the 4 main alternatives, but I don't have time to run it several times to get the means and plot the times for several inputs... So here's the code if anybody wants to try it:

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

It takes 2 arguments, the first is the number of iterations (each function run with repeat times arg from 1..n) and the second is the string to repeat.

So far, a quick inspection of the times running with different inputs leaves the ranking something like this (better to worse):

  1. Iterative StringBuilder append (1x).
  2. Recursive concatenation log2 invocations (~3x).
  3. Recursive concatenation linear invocations (~30x).
  4. Iterative concatenation linear (~45x).

I wouldn't ever guessed that the recursive function was faster than the for loop :-o

Have fun(ctional xD).

8 Comments

+1 for recursion and obviously being a lisp hacker. I don't think this is so inefficient either, string concatenation isn't the warcrime it once was, because + really is just a stringBuilder UTH. See stackoverflow.com/questions/47605/java-string-concatenation and schneide.wordpress.com/2009/02/23/… . I wonder how much all those stack pushes and pops from the recursion cost, or if hotspot takes care of them. Really wish I had the free time to benchmark it. Someone else maybe?
@e5: fortran is right; this solution could be made more efficient. This implementation will unnecessarily create a new StringBuilder (and a new String) for each recursion. Still a nice solution though.
@e5 I'd wish I were a Lisp hacker xD... If I were, I would have used a tail recursive function :-p
Microbenchmarks don't work well in Java. Trying to measure the speed of your implementations like that is not good.
The reason why the repeatIc is slower than even the simple recursion is that compilers typically translate string concatenation to StringBuilder code which helps in complex scenarios but implies even more copying operations in the case of concatenating two strings. So, in this specific case, using tmp = tmp.concat(s); will be more efficient than tmp += s; This does not apply when you compile for Java 9 or newer with javac, as the code will use StringConcatFactory then, which will likely handle the two string case with the same performance as concat.
|
21

This contains less characters than your question

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

8 Comments

It contains more characters than my answer StringUtils.repeat(str, n).
Unless you're already using Apache Commons, this answer is a lot less hassle - no downloading another library, including it in your classpath, making sure its license is compatible with yours, etc.
Please, never return null - in that case return an empty string, allowing you to always use the returned value unchecked. Otherwise, what I would recommend the poster to use.
Well, there are three ways to handle if s is null. 1. Pass the error (return null), 2. Hide the error (return ""), 3. Throw an NPE. Hiding the error and throwing an NPE are not cool, so I passed the error.
@EthanHeilman add the 2MB worth of commons-lang3.3.1-sources and you're not that good anymore ;) But if someone already has commons-lang, I support your answer.
|
9

based on fortran's answer, this is a recusive version that uses a 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();
}

1 Comment

looping rather than recursion would reduce the # of stack frames for large numbers of repeats.
7

using Dollar is simple as typing:

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

PS: repeat works also for array, List, Set, etc

2 Comments

is the assertThat() method really needed?
Link in answer gives "404 | Repository not found".
7

I wanted a function to create a comma-delimited list of question marks for JDBC purposes, and found this post. So, I decided to take two variants and see which one performed better. After 1 million iterations, the garden-variety StringBuilder took 2 seconds (fun1), and the cryptic supposedly more optimal version (fun2) took 30 seconds. What's the point of being cryptic again?

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

1 Comment

I makes sense that the second one would take much longer. It is performing a string search and then modifying the string character by character.
7

OOP Solution

Nearly every answer proposes a static function as a solution, but thinking Object-Oriented (for reusability-purposes and clarity) I came up with a Solution via Delegation through the CharSequence-Interface (which also opens up usability on mutable CharSequence-Classes).

The following Class can be used either with or without Separator-String/CharSequence and each call to "toString()" builds the final repeated String. The Input/Separator are not only limited to String-Class, but can be every Class which implements CharSequence (e.g. StringBuilder, StringBuffer, etc)!

Source-Code:

/**
 * 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);
    }
}

Usage-Example:

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

Example-Output:

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

Comments

6

using only JRE classes (System.arraycopy) and trying to minimize the number of temp objects you can write something like:

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

EDIT

and without loops you can try with:

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

using Collections is even shorter:

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

however I still like the first version.

8 Comments

-1: too clever by half. If your aim is to make you code readable or efficient, these "solutions" are not a good idea. 'repeat' could simply be rewritten using a StringBuilder (setting the initial capacity). And 'repeat2' / 'repeat3' are really inefficient, and depend on the unspecified syntax of the String produced by String[].toString().
@Thorb: absolutely, with this code you cannot use "metacharacter", [],
@Stephen: the question was edited to request explicitly no loops. A StringBuilder based answer was already provided so I avoided to post a duplicate
@Stephan: I cannot figure out the downvote. My edited answer is loop-free as requeted. There are no requests about efficiency. I think that this question is just an intellectual effort to produce a concatenation without a loop.
@Stephan: String produced via Collection.toString (and Arrays.toString) are clearly specified in AbstractCollection.toString: " The string representation consists of a list of the collection's elements in the order they are returned by its iterator, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (comma and space)."
|
6

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

Comments

5

If speed is your concern, then you should use as less memory copying as possible. Thus it is required to work with arrays of chars.

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

To test speed, a similar optimal method using StirngBuilder is like this:

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

and the code to test it:

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

}

And here the run results from my system:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

Note that the test for loop is to kick in JIT and have optimal results.

Comments

5

a straightforward one-line solution:
requires Java 8

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );

Comments

4

for the sake of readability and portability:

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

Comments

3

Seeing a number of StringBuilder related answers, I believe it's also worth mentioning that there are new StringBuilder.repeat and StringBuffer.repeat methods added in Java 21 to simplify the appending of multiple copies of characters or strings:

System.out.println(new StringBuilder().repeat('A', 10)); // AAAAAAAAAA

System.out.println(new StringBuilder().repeat("A1", 2)); // A1A1

Comments

3

If you are worried about performance, just use a StringBuilder inside the loop and do a .toString() on exit of the loop. Heck, write your own Util class and reuse it. It will have five lines of code at most.

1 Comment

btw, since this got edited (@Sae1962), the String class has a repeat(int) method since Java 11 -- Heck, no Util class needed :-)
2

I really enjoy this question. There is a lot of knowledge and styles. So I can't leave it without show my 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);
    }
}

Do you like it?

1 Comment

In my more extreme test, I produce a 1,700,000,000 (1.7 gigas) string repeat length,, using -Xms4937m
2
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);
}

Comments

2

Simple loop

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

1 Comment

pass times to StringBuilder constructor.
2

Try this out:

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

Comments

2

Using recursion, you can do the following (using ternary operators, one line max):

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

I know, it's ugly and probably not efficient, but it's one line!

4 Comments

This is the approach I would take but why do more checks than is needed? return number > 0 ? string + repeat(string, number-1) : "";
Oh, seems niczm25 answered with it below
@Fering main reason so that this way is O(log N) average rather than O(N) always. Slightly more optimization than the other one, though still bad nevertheless.
and never call it with number being negative or zero
2

If you only know the length of the output string (and it may be not divisible by the length of the input string), then use this method:

static String repeat(String s, int length) {
    return s.length() >= length ? s.substring(0, length) : repeat(s + s, length);
}

Usage demo:

for (int i = 0; i < 50; i++)
    System.out.println(repeat("_/‾\\", i));

Don't use with empty s and length > 0, since it's impossible to get the desired result in this case.

Comments

1

Despite your desire not to use loops, I think you should use a 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();
}

Your reasons for not using a for loop are not good ones. In response to your criticisms:

  1. Whatever solution you use will almost certainly be longer than this. Using a pre-built function only tucks it under more covers.
  2. Someone reading your code will have to figure out what you're doing in that non-for-loop. Given that a for-loop is the idiomatic way to do this, it would be much easier to figure out if you did it with a for loop.
  3. Yes someone might add something clever, but by avoiding a for loop you are doing something clever. That's like shooting yourself in the foot intentionally to avoid shooting yourself in the foot by accident.
  4. Off-by-one errors are also mind-numbingly easy to catch with a single test. Given that you should be testing your code, an off-by-one error should be easy to fix and catch. And it's worth noting: the code above does not contain an off-by-one error. For loops are equally easy to get right.
  5. So don't reuse variables. That's not the for-loop's fault.
  6. Again, so does whatever solution you use. And as I noted before; a bug hunter will probably be expecting you to do this with a for loop, so they'll have an easier time finding it if you use a for loop.

9 Comments

-1. Here's two exercises for you: a) run your code with repetitions = -5. b) download Commons Lang and run repeatString('a', 1000) a million times in a loop; do the same with your code; compare the times. For extra credit do the same with repeatString('ab', 1000).
Are you arguing that your code is more readable then StringUtils.repeat("ab",1000)? Because that was my answer that you've downvoted. It also performs better and has no bugs.
Read the 2nd sentence in the question you're quoting. "I try to avoid for loops at all costs because" was added to the question as a clarification in response to Andrew Hare's answer after my reply - not that it matters because if the position you're taking is "answer is bad if loop is used anywhere" there are no answers to the OP question. Even dfa's solutions - inventive as they are - use for loops inside. "jar hell" was replied to above; commons lang is used in every decent-sized application anyway and thus doesn't add a new dependency.
@ChssPly76 at this point I'm pretty sure imagist is trolling. I really have a hard time seeing how anyone could read what I wrote and seriously think the responses typed above.
@ChssPly76 my answers don't have any loops at all :-p
|
1

Consolidated for quick reference:

public class StringRepeat {

// Java 11 has built-in method - str.repeat(3);
// Apache - StringUtils.repeat(3);
// Google - Strings.repeat("",n);
// System.arraycopy

static String repeat_StringBuilderAppend(String str, int n) {

    if (str == null || str.isEmpty())
        return str;

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < n; i++) {
        sb.append(str);
    }
    return sb.toString();
}

static String repeat_ArraysFill(String str, int n) {
    String[] strs = new String[n];
    Arrays.fill(strs, str);
    return Arrays.toString(strs).replaceAll("\\[|\\]|,| ", "");
}

static String repeat_Recursion(String str, int n) {
    if (n <= 0)
        return "";
    else
        return str + repeat_Recursion(str, n - 1);
}

static String repeat_format1(String str, int n) {
    return String.format(String.format("%%%ds", n), " ").replace(" ", str);
}

static String repeat_format2(String str, int n) {
    return new String(new char[n]).replace("\0", str);
}

static String repeat_format3(String str, int n) {
    return String.format("%0" + n + "d", 0).replace("0", str);
}

static String repeat_join(String str, int n) {
    return String.join("", Collections.nCopies(n, str));
}

static String repeat_stream(String str, int n) {
    return Stream.generate(() -> str).limit(n).collect(Collectors.joining());
}

public static void main(String[] args) {
    System.out.println(repeat_StringBuilderAppend("Mani", 3));
    System.out.println(repeat_ArraysFill("Mani", 3));
    System.out.println(repeat_Recursion("Mani", 3));
    System.out.println(repeat_format1("Mani", 3));
    System.out.println(repeat_format2("Mani", 3));
    System.out.println(repeat_format3("Mani", 3));
    System.out.println(repeat_join("Mani", 3));
    System.out.println(repeat_stream("Mani", 3));

}

}

Comments

0

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

1 Comment

I don't think there is much else you can do... excet maybe an AOT!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.