774

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.

Lii
  • 11,553
  • 8
  • 64
  • 88
Ethan Heilman
  • 16,347
  • 11
  • 61
  • 88
  • 47
    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. – Imagist Aug 05 '09 at 21:39
  • 1
    With those concerns, consider having exhaustive unittests for your code. This allows you to just show the unit test when documentation is needed. – Thorbjørn Ravn Andersen Aug 05 '09 at 23:01
  • 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 – Pyrolistical Aug 05 '09 at 23:40
  • 8
    @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. – Ethan Heilman Aug 06 '09 at 00: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. – Ethan Heilman Aug 06 '09 at 00:51
  • @e5: Those are good things, but they don't always follow from using library functions. What people are saying to you is that inappropriate use of library functions (e.g. "avoiding loops at all costs") can decrease readability, increase bug surface area [*], and make your application catastrophically slower. [ Libraries can have bugs too!] – Stephen C Aug 06 '09 at 10:03
  • 1
    @Stephen C , Oh certainly, I completely agree with thing you just said! When I say "avoid loops at all costs", I'm exaggerating my position a bit for dramatic effect. For loops are necessary and good, but I do see an overuse of them in my code and others. I am merely trying to improve my style. – Ethan Heilman Aug 06 '09 at 14:29
  • 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. – AgostinoX Sep 21 '11 at 21:01
  • 2
    @AgostinoX Looking back at this question I realize one more problem with for loops. They specify the order in which actions must be performed when most of the time the engineer only wants to perform some action on every element in a list (regardless of order). This order dependency makes it much harder for compilers to parallelize code. I think the python map function has the right of it: http://docs.python.org/library/functions.html#map – Ethan Heilman Sep 21 '11 at 21:31
  • @AgostinoX Raises pitchfork in total agreement. "Death to the for loop, long live readability"! – Ethan Heilman Sep 21 '11 at 21:35
  • 1
    @e5:another good reason to avoid loops is that java has already introduced iterators with the sole scope of alleviate the loops declaration.There has been such an heavy effort to that purpose.Improving the String API a bit would allow for the complete elimination of "obvious" loops from code at a very low cost.And a much greater (yet understimated) benefit.The time it takes to understand the simplest loop is much greater than the time spent in reading "repeat" word. String[] x = {"think?", "you", "dont"}; for (int i=x.length-1;i>=0;i--) { System.out.println(x[i]); } – AgostinoX Sep 21 '11 at 21:44
  • 1
    @e5: the order question is correct but I think that you cannot turn a procedural language into a declarative one "just in case". I don't know if you feel so relaxed when iterating collection items and deleting some of them because "you only want to perform an action on each element" leaving to the library implementation "not to do a mess". Perhaps you would study the API more in deep. If you had not time, you probably choose a fail-proof procedural approach like a downto-removal :-) – AgostinoX Sep 21 '11 at 21:51
  • 1
    @e5: however, i think that several of these reasons are pretty "strict". perhaps enough to start a JCP request. wouldn't it be wonderful? – AgostinoX Sep 21 '11 at 22:10
  • 1
    "Clever" code should be avoided. `for` loops should not. Make the code do what it looks like, and use many lines if needed. Your compiler will make it all small and clever - out of sight. – Floris Apr 24 '14 at 04:04
  • 3
    @Floris "Clever" code __should__ be avoided, I agree. But for-loops are "clever" code you have just become used to them. Consider that the for-loop relies on a mathematical relationship between how we store strings in arrays (a fairly arbitrary, machine dependent choice) and a periodically increasing integer. Before you disagree try explaining how you would 'repeat a string using for-loops' to a non-programmer. – Ethan Heilman Apr 24 '14 at 14:47
  • 2
    @EthanHeilman here goes: "we store the string as a list of characters, each in a numbered box. If I need a string that is 100 long, I first put a character in box 1, then box 2, all the way until I get to box 100. Then I stop adding characters. " That seems to describe the for loop quite well. I decided not to explain the "zero offset" since that is irrelevant to the explanation to the non-programmer. – Floris Apr 24 '14 at 15:24
  • 1
    If you're on Java 11, you can use `String::repeat` - see [this answer](https://stackoverflow.com/a/49065337/2525313). – Nicolai Parlog Mar 02 '18 at 08:32
  • 1
    repeats = "abc" * 3 Python is much more condensed than java – Golden Lion Jul 27 '21 at 15:00

32 Answers32

1007

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.

Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
user102008
  • 30,736
  • 10
  • 83
  • 104
  • 26
    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` – Amarok Dec 13 '12 at 18:10
  • 44
    While this is very clever (+1) I think it pretty much proves the point that for loops often make for clearer code – Richard Tingle Jun 25 '13 at 11:53
  • 94
    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. – dansalmo Jan 09 '14 at 16:15
  • 11
    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. – Rudi Kershaw Feb 20 '14 at 10:07
  • 11
    For better performance `...replace('\0', str)` should be used instead of the String version. – user686249 Oct 06 '14 at 16:51
  • 12
    @user686249: There are only `replace(char oldChar, char newChar)` and `replace(CharSequence target, CharSequence replacement)` so I don't see how that could work – user102008 Oct 06 '14 at 18:18
  • @fortran I'm sorry for that mistake..... this should work `Integer.toString(Math.pow(10, n)).replace("1", "").replace("0", str);` or this `Integer.toBinaryString(Math.pow(2, n)).replace("1", "").replace("0", str);` DON'T use this for large number lol – Valen Apr 04 '15 at 17:06
  • 3
    I needed to use replaceAll() to make it work, and it's 10 times slower than a new StringBuilder(length) and a `while(repeat-- > 0) { sb.apend(word)}` – juanmf Apr 07 '15 at 18:32
  • So the `\0` end of string delimiter was resurrected from `C` ? What are other useful applications of it in `java` ? – WestCoastProjects Jul 21 '18 at 20:47
  • 6
    @javadba: No, this has nothing to do with "end of string delimiters" (which don't exist here anyway). Rather, when you create a new array, all elements are initialized to the zero value of the type; in the case of `char`, that's the 0 character. We simply do a replacement on each occurrence of that character. – user102008 Jul 22 '18 at 04:13
  • 4
    @user102008 To be precise: it's the [_null_ character](https://en.wikipedia.org/wiki/Null_character), not "the 0 [zero] character". – Gerold Broser Jan 21 '19 at 08:33
  • @Caner answer is readable: `String.join("", Collections.nCopies(n, s));` https://stackoverflow.com/questions/1235179/simple-way-to-repeat-a-string/6857936#6857936 – user1742529 Jan 06 '22 at 11:08
544

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);
Nayuki
  • 17,911
  • 6
  • 53
  • 80
Caner
  • 57,267
  • 35
  • 174
  • 180
  • 5
    The former causes an exception when `n` is zero. –  Jun 04 '17 at 11:19
  • The java 8 example does not compile -> Type mismatch: cannot convert from List to CharSequence – Arigion Aug 08 '17 at 11:18
  • 8
    @Arigion `s` has to be String, not a `Char` – Caner Aug 09 '17 at 09:37
  • @Caner Thanks. My bad, I apologize. Apparently I was too tired yesterday. Sorry about downvoting. I'll remove the downvote as soon as I could (it's blocked until question is edited) – Arigion Aug 10 '17 at 06:04
  • @Arigion no problem, made it clear now that s is a string – Caner Aug 10 '17 at 08:42
  • 4
    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! – rococo Aug 21 '21 at 19:07
394

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
 */ 
Lii
  • 11,553
  • 8
  • 64
  • 88
Nicolai Parlog
  • 47,972
  • 24
  • 125
  • 255
  • 8
    @Nicolai source code for it, just in case someone cares http://hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/share/classes/java/lang/String.java#l2984 – Eugene May 04 '18 at 12:27
  • 12
    i have not even seen java *9* yet on the street (and will not for a *long* time..) - and *11* is apparently set to ship.. – WestCoastProjects Jul 21 '18 at 20:38
  • 5
    Probably obvious, but you can call this method on a string literal too: `"abc".repeat(3)` – Boann Jun 20 '19 at 01:56
323

Commons Lang StringUtils.repeat()

Usage:

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

repeated.equals("abcabcabc");
Pang
  • 9,564
  • 146
  • 81
  • 122
ChssPly76
  • 99,456
  • 24
  • 206
  • 195
  • 105
    using a one-method-dependency for the simplicity's sake in the long run can resulting in a jar-hell – dfa Aug 05 '09 at 20:03
  • 83
    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. – Ethan Heilman Aug 05 '09 at 20:05
  • 3
    The solution to jar-hell is a managed build depency system such as maven. Import away. – Markus Koivisto Aug 05 '09 at 20:06
  • What makes you think that this doesn't simply tuck the for loop away in another function? (Criticism 1) – Imagist Aug 05 '09 at 21:46
  • 11
    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. – ChssPly76 Aug 05 '09 at 21:59
  • 31
    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! – Ethan Heilman Aug 05 '09 at 22:24
  • 1
    Migrate to Maven to avoid a for-loop?? Interesting turn this is taking. – Thorbjørn Ravn Andersen Aug 05 '09 at 22:49
  • 7
    @Thorbjørn Ravn Andersen - it can get a LOT more interesting if things keep being taken out of context – ChssPly76 Aug 05 '09 at 23:03
  • 7
    @e5 - The use and reuse of the commons classes, StringUtils especially, reduces maintenence load in a number of ways. Simple, descriptive method names, sensible defaults and null handlings and a stable codebase all make it easier to identfy where bugs are more likely to reside. One idiom I encourage is that loop control always uses "i"; this forces only one loop per method, which means the common problem of incrementing the wrong thing is removed. – Michael Rutherfurd Aug 06 '09 at 01:06
  • 2
    @Michael Rutherfurd, those are rules to live by! I've been following the "one for loop per method rule" for a few months now and it has improved the quality and readability of my code dramatically. Have trouble obeying "one for loop per method" when I'm taking the Cartesian product of two arrays. I should post a question on how to do that better. Java should to add the warning 'consider using stringUtils'. – Ethan Heilman Aug 06 '09 at 01:40
  • The Apache commons repeat uses StringBuffer internally. This will have some overhead in synchronization over your rolling your own implmementation that makes use of StringBuilder. – pjp Aug 06 '09 at 09:34
  • @pjp I hadn't heard that, can you provide a link to back this up? – Ethan Heilman Aug 06 '09 at 15:29
  • Synchronization of what? StringUtils.repeat() is a static method using internal StringBuffer. – ChssPly76 Aug 06 '09 at 18:06
  • 1
    As soon as you use a framework or tool the Apache Commons will be in your project. I bet we already have `StringUtils` in our projects. – Alireza Fattahi Mar 06 '19 at 08:14
151

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")));
Boann
  • 48,794
  • 16
  • 117
  • 146
  • 7
    thank you! For android TextUtils.join() can be used instead of String.join() – MinaHany Dec 11 '16 at 07:34
  • 2
    Thank you for this answer. It's seems to be the cleanest way without using any external API oder utility method! very good!! – Andreas M. Oberheim Jan 06 '17 at 10:07
  • 2
    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. – DroidOS Oct 15 '18 at 08:10
  • 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();` – ATOMP Apr 24 '22 at 20:10
104

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);
spongebob
  • 8,370
  • 15
  • 50
  • 83
I. J. Kennedy
  • 24,725
  • 16
  • 62
  • 87
  • 5
    Amazing :-) Although beware of n becoming zero…! – Yang Meyer Jan 12 '10 at 14:14
  • http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#replace%28char,%20char%29 - replace() accepts two char parameters. Not Strings! – Vijay Dev Feb 19 '10 at 14:37
  • 1
    I think he meant `replaceAll` – fortran Mar 11 '10 at 10:15
  • 4
    @Vijay Dev & fortran: No, he meant `replace()`. In Java 1.5+, there is an overloaded version of `replace()` that takes two `CharSequence`s (which include `String`s): http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#replace%28java.lang.CharSequence,%20java.lang.CharSequence%29 – user102008 Feb 04 '11 at 22:32
  • 8
    @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 – fortran Jul 15 '13 at 14:49
  • 17
    You can make the solution less ugly and easier to understand: **String.format("%0"+n+"d", 0).replace("0", s)** – Artur Nov 26 '13 at 08:58
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);
Jack
  • 20,735
  • 11
  • 48
  • 48
  • 4
    ... and get 3Mb of new dependencies. – MonoThreaded May 25 '18 at 20:57
  • 6
    @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. – Jack May 25 '18 at 23:53
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());
}
Alexis C.
  • 91,686
  • 21
  • 171
  • 177
  • 6
    ... or `return IntStream.range(0, times).mapToObj(i -> str).collect(joining());` which parallelizes better – Alexis C. Oct 14 '15 at 18:53
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).

fortran
  • 74,053
  • 25
  • 135
  • 175
  • 1
    +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 http://stackoverflow.com/questions/47605/java-string-concatenation and http://schneide.wordpress.com/2009/02/23/about-string-concatenation-in-java-or-dont-fear-the/ . 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? – Ethan Heilman Aug 06 '09 at 01:31
  • @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. – rob Aug 06 '09 at 03:02
  • 3
    @e5 I'd wish I were a Lisp hacker xD... If I were, I would have used a tail recursive function :-p – fortran Aug 06 '09 at 08:41
  • 1
    Microbenchmarks don't work well in Java. Trying to measure the speed of your implementations like that is not good. – ceklock Dec 09 '12 at 01:08
  • @tecnotron I know, but still they are better than nothing... And the only 'surprise' was the slight difference between the naive loop concatenation and linear recursion. – fortran Dec 10 '12 at 11:55
  • The recursion is a loop. –  Jul 26 '14 at 14:05
  • The loop is a recursion. – fortran Jul 29 '14 at 15:33
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();
}
Community
  • 1
  • 1
Pyrolistical
  • 27,624
  • 21
  • 81
  • 106
  • 7
    It contains more characters than my answer StringUtils.repeat(str, n). – Ethan Heilman Aug 05 '09 at 19:32
  • 8
    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. – Paul Tomblin Aug 05 '09 at 19:44
  • 7
    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. – Thorbjørn Ravn Andersen Aug 05 '09 at 22:52
  • 7
    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. – Pyrolistical Aug 05 '09 at 23:34
  • 2
    @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. – TWiStErRob Oct 03 '13 at 20:02
  • 1
    @Pyrolistical "passing the error" as you call it is not a good thing to do. It makes it harder to figure out where the error originally came from. You could reasonably do what TWiStErRob said and treat `null` as `"null"` (as the StringBuilder already does). Otherwise, the right thing to do is throw an NPE. If the caller passes garbage input, for which there is no sensible output, it's right that they should get garbage thrown back at them. – Boann Oct 26 '14 at 14:01
  • 1
    Is it `repeat`'s task to forbid the use of null and crash your program if you do? Returning `null` when given a `null` is the most neutral way to handle this particular input. – Florian F Jul 08 '17 at 05:33
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();
}
Community
  • 1
  • 1
dfa
  • 114,442
  • 31
  • 189
  • 228
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);
}
Bob
  • 71
  • 1
  • 1
  • 3
    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. – Ethan Heilman Dec 06 '12 at 16:14
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

dfa
  • 114,442
  • 31
  • 189
  • 228
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
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.

dfa
  • 114,442
  • 31
  • 189
  • 228
  • 6
    -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(). – Stephen C Aug 05 '09 at 23:14
  • @Thorb: absolutely, with this code you cannot use "metacharacter", [], – dfa Aug 06 '09 at 02:22
  • @Stephen: the question was edited to request **explicitly** no loops. A StringBuilder based answer was already provided so I avoided to post a duplicate – dfa Aug 06 '09 at 02:25
  • @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. – dfa Aug 06 '09 at 02:50
  • @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)." – dfa Aug 06 '09 at 03:04
  • @dfa: I take back my point about toString() being unspecified. (I didn't know that ...). But I don't read the OP as saying that this is merely an intellectual effort. Rather I think he is serious ... and seriously misguided ... and might even copy-and-paste one of your "too clever" solutions into his code! – Stephen C Aug 06 '09 at 04:48
  • IF you're only interested in repeating a single char, then Arrays.fill would be lovely. i.e. char[] data = new char[count]; Arrays.fill(data, toRepeat); return new String(data); – laher Apr 10 '14 at 22:14
  • Your versions using `replace` are catastrophically broken, because they remove all bracket characters and comma-space sequences in the inputs. Your basic loop version is alright, although the input value coercion is a bit dodgy, and you could avoid calling `toCharArray()` by using [`String.getChars`](http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#getChars-int-int-char:A-int-). – Boann Oct 26 '14 at 12:02
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();
  }
Simon
  • 2,686
  • 2
  • 31
  • 43
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.

Panayotis
  • 1,792
  • 23
  • 32
5

a straightforward one-line solution:
requires Java 8

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );
Kaplan
  • 2,572
  • 13
  • 14
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);
}
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
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. 5 Lines of code max.

WolfmanDragon
  • 7,851
  • 14
  • 49
  • 61
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?

Daniel De León
  • 13,196
  • 5
  • 87
  • 72
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);
}
Ethan Heilman
  • 16,347
  • 11
  • 61
  • 88
falcon
  • 372
  • 3
  • 19
2

Simple loop

public static String repeat(String string, int times) {
    StringBuilder out = new StringBuilder();
    while (times-- > 0) {
        out.append(string);
    }
    return out.toString();
}
Codler
  • 10,951
  • 6
  • 52
  • 65
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;
}
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!

hyper-neutrino
  • 5,272
  • 2
  • 29
  • 50
  • This is the approach I would take but why do more checks than is needed? return number > 0 ? string + repeat(string, number-1) : ""; – Fering Dec 07 '18 at 13:50
  • Oh, seems niczm25 answered with it below – Fering Dec 07 '18 at 13:52
  • @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. – hyper-neutrino Dec 07 '18 at 18:49
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.

John McClane
  • 3,498
  • 3
  • 12
  • 33
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.
Imagist
  • 18,086
  • 12
  • 58
  • 77
  • 3
    -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)`. – ChssPly76 Aug 05 '09 at 22:04
  • Fixed the first issue. As for the second issue, right, because speed is the ONLY concern. Given that the OP considers for loops to be the bane of programming, he's more concerned about readability than micro-optimizations. – Imagist Aug 05 '09 at 22:17
  • 2
    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. – ChssPly76 Aug 05 '09 at 22:19
  • So you're coming out and admitting that you downvoted my answer because I downvoted yours, not on the merits of my answer? For your information, I downvoted your answer, not because of readability, but because as dfa said, "using a one-method-dependency for the simplicity's sake in the long run can resulting in a jar-hell" in addition to my own criticism, "What makes you think that this doesn't simply tuck the for loop away in another function?". Since the first is a concern and the second is obviously a concern to the OP, I thought my downvote was justified. – Imagist Aug 05 '09 at 22:27
  • "Admitting"? I explicitly said "-1" and specified the reasons why. "Jar hell" is a non-issue; it's been addressed in comments above. OP was not trying to avoid loops at all costs; he did not want to write one if there was already a library function that would do this task for him. Your code (which uses the loop; is not as readable; had a bug; and doesn't perform well) is a perfect illustration why. – ChssPly76 Aug 05 '09 at 22:40
  • "Jar hell" may be a non-issue with Maven, but one shouldn't have to install an entire dependency system and a library just to implement a few lines of code. If he plans to use it elsewhere, fine, but I saw no indication of that in the original post. As for avoiding loops at all costs: the OP said, "I try to avoid for loops at all costs because:" and listed a bunch of reasons. So I think that he WAS trying to avoid loops at all costs. – Imagist Aug 05 '09 at 22:48
  • 2
    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 Aug 05 '09 at 23:01
  • 2
    @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. – Ethan Heilman Aug 06 '09 at 00:37
  • 1
    @ChssPly76 my answers don't have any loops at all :-p – fortran Aug 06 '09 at 13:54
0

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?

Community
  • 1
  • 1
niczm25
  • 169
  • 1
  • 2
  • 13
0

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

}

}

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

alexmherrmann
  • 1,055
  • 2
  • 9
  • 17
-1
public static String rep(int a,String k)

       {
           if(a<=0)
                return "";
           else 
           {a--;
               return k+rep(a,k);
       }

You can use this recursive method for you desired goal.

-3
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.

Will
  • 73,905
  • 40
  • 169
  • 246