Eduardo
Eduardo

Reputation: 2279

Java 8 convert integers to String with Lambda

I'm trying to create a function which returns a random string of alphabetic characters, but I'm trying to do it using lambdas, my function looks like:

public static String nextString() {
  return IntStream.range(0, 10).map(i -> getRandomChar()).XXX
}

private static Character getRandomChar() {
  //returns a random Character object
}

I don't know what to set on XXX.

I fixed it in a similar way by doing:

public static String nextString() {
    StringBuilder randomString = new StringBuilder();
    IntStream.range(0, stringLenght).forEach(i -> randomString.append(getRandomChar()));
    return randomString.toString();
}

But I'd prefer not to create a new StringBuilder each time the method is used and keep states and variables for a simple method.

Upvotes: 3

Views: 3812

Answers (2)

Holger
Holger

Reputation: 298389

It’s not clear what getRandomChar() does that it is worth building another Stream operation around it. It’s much simpler to stream over random values in the first place.

E.g., the following code generates random strings consisting of upper case letters in the A-Z range:

public static String nextString() {
    return ThreadLocalRandom.current().ints(stringLength, 'A', 'Z'+1)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

If the intended characters do not form a consecutive range, you can use a string constant naming the allowed characters, e.g.

public static String nextString() {
    String allowed = "XO+";
    return ThreadLocalRandom.current().ints(stringLength, 0, allowed.length())
        .map(allowed::charAt)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

Granted, this collector doesn’t hide the StringBuilder the same way, Collectors.joining() does, but on the other hand, this operation has no boxing overhead and doesn’t create temporary strings.

You can use a similar operation to built the character pool String:

static final String ASCII_LETTERS_AND_NUMBERS =
        IntStream.concat(IntStream.concat(
            IntStream.rangeClosed('A', 'Z'), IntStream.rangeClosed('a', 'z')),
            IntStream.rangeClosed('0', '9'))
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
public static String nextString() {
    return ThreadLocalRandom.current()
        .ints(stringLength, 0, ASCII_LETTERS_AND_NUMBERS.length())
        .map(ASCII_LETTERS_AND_NUMBERS::charAt)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

or, to challenge the reader of the random string:

static final String ALL_LETTERS_AND_NUMBERS =
    IntStream.rangeClosed(32, Character.MAX_VALUE)
        .filter(Character::isLetterOrDigit)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
public static String nextString() {
    return ThreadLocalRandom.current()
        .ints(stringLength, 0, ALL_LETTERS_AND_NUMBERS.length())
        .map(ALL_LETTERS_AND_NUMBERS::charAt)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

Upvotes: 1

Oleksandr Bondarchuk
Oleksandr Bondarchuk

Reputation: 1053

Something like this:

public static String nextString() {
    return IntStream.range(0, 10).boxed().map(i -> getRandomChar(i)).collect(Collectors.joining());
}

private static String getRandomChar(int i) {
    return String.valueOf((char)i);
}

Upvotes: 4

Related Questions