Sun
Sun

Reputation: 3564

Find index of the element in Java 8 stream foreach

There are already some posts looks relative to this, I went through them, but those not solved my problem:

I have a method and some logic, I have to do code optimize using streams.

My method is: (here I am trying to print the emails in a formatted way)

public static StringBuilder printEmailsListFormat(ArrayList<String> a) {

    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < a.size(); i++) {
        if (i % 3 ==0)
        {
            sb.append(String.format("%-45s", a.get(i)));
            sb.append("\n");
        }
        else
            sb.append(String.format("%-45s", a.get(i)));
    }
    return sb;
}

I have to optimize this code.

Upvotes: 1

Views: 769

Answers (3)

Michael
Michael

Reputation: 44110

This is about the best you can do. It's pretty ugly, because streams are not aware of the list indices. It is not a very good candidate for converting to use streams.

public static StringBuilder printEmailsListFormat(ArrayList<String> a) {
    return IntStream.range(0, a.size())
        .mapToObj(i -> {
            String format = "%-45s";
            if (i % 3 == 0) format += "\n";
            return String.format(format, a.get(i));
        })
        .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append);
}

Upvotes: 1

Holger
Holger

Reputation: 298123

If you want to optimize your code, you should not switch to the Stream API. Instead, change it to use a single Formatter, instead of one for each element (hidden inside String.format) and avoid the temporary strings created by String.format:

public static StringBuilder printEmailsListFormat(List<String> a) {
    StringBuilder sb = new StringBuilder();
    Formatter formatter = new Formatter(sb);
    for(int i = 0; i < a.size(); i++) {
        formatter.format("%-45s", a.get(i));
        if(i % 3 ==0) sb.append("\n");
    }
    return sb;
}

Given the simplicity of the format in this specific case, you may even eliminate the Formatter completely:

static final String EMPTY_CELL = String.format("%45s", ""); //JDK11: " ".repeat(45);

public static StringBuilder printEmailsListFormat(List<String> a) {
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < a.size(); i++) {
        String s = a.get(i);
        sb.append(s);
        if(s.length() < EMPTY_CELL.length())
            sb.append(EMPTY_CELL, s.length(), EMPTY_CELL.length());
        if(i % 3 ==0) sb.append("\n");
    }
    return sb;
}

Upvotes: 2

Chaarmann
Chaarmann

Reputation: 154

You can only parallelize and therefore speed up the formatting of the strings, but not the concatenation of the formatted parts, since they must be in order.

You could also concatenate the formatted parts via stream, but a for-loop is faster. So you would get:

// just some example values
ArrayList<String> a = new ArrayList(Arrays.asList("string1", "string2", "string3", "string4", "string5"));
// formatting them in parallel
List<String> formatted = a.parallelStream().map(s -> String.format("%-45s", s)).collect(Collectors.toList());
// concatenating them in order
StringBuilder sb = new StringBuilder();
for (ListIterator<String> i = formatted.listIterator(); i.hasNext();) {
    sb.append(i.next());
    if (i.previousIndex() % 3 == 0) {
        sb.append("\n");
    }
}
System.out.println("output: " + sb);

The output is:

output: string1                                      
string2                                      string3                                      string4                                      
string5        

Remark: consider using System.getProperty("line.separator") instead of "\n".

Upvotes: 0

Related Questions