"Multiplying" 2 lists of Strings together in Java 8 The following method is part of a class that imports zip archives, and part of that class's job is to verify that a given zip archive contains "complete filesets". A "complete fileset" is one such that, for a given file name prefix, there exists a file in the zip archive with that prefix and each suffix. There are always 3 suffixes and they are always the same 3.

For example, say there are file names prefixes A, B, and C, and the suffixes are X, Y, and Z. Then the file names found in the zip archive should be AX, AY, AZ, BX, BY, BZ, CX, CY, and CZ.

This method is used to create the list of expected file names in order to verify that they all exist within the zip archive.

Here is the method in question:

public static List&lt;String&gt; multiply( List&lt;String&gt; list1, List&lt;String&gt; list2 ) {
    return list1.stream()
        .map( s1 -&gt; {
            return list2.stream()
                .map( s2 -&gt; s1 + s2 )
                .collect( Collectors.toList() );
        })
        .flatMap( List::stream )
        .collect( Collectors.toList() );
}


I was wondering if, maybe, there is a clearer or more concise way to accomplish this? I realize it can be done with a couple of for loops, but I would prefer using Java 8 streams, as I would like to practice and learn the API. Also, I'm not sure if "multiply" is the right thing to call this operation.

Here is the unit test for the method if it helps to clarify the usage and intent:

@Test
public void testMultiply() {
    List&lt;String&gt; list1 = Lists.newArrayList( "A", "B", "C" );
    List&lt;String&gt; list2 = Lists.newArrayList( "D", "E", "F" );
    List&lt;String&gt; result = Lists.newArrayList(
        "AD", "AE", "AF",
        "BD", "BE", "BF",
        "CD", "CE", "CF");
    Assert.assertEquals( result, multiply( list1, list2 ) );
}
Method name

I agree with you, multiply() does sound a bit odd for lists of non-numbers... perhaps combine() or cartesianProduct() are arguably better names?

Lambdas

'Single-shot' lambda definitions does not require the use of { return ...; }:

.map( s1 -&gt; list2.stream().map( s2 -&gt; s1 + s2 ).collect( Collectors.toList() ) )


Actually, when you are mapping an element to a Collection, only to flatMap() it immediately afterwards, you can probably do without the inner collect():

return list1.stream()
            .flatMap( s1 -&gt; list2.stream().map( s2 -&gt; s1 + s2 ) )
            .collect( Collectors.toList() );