Multiplying corresponding integers using streams While reviewing Multiplying Lists, I got the impression that the problem was naturally suited to Java 8 streams.  Unfortunately, since there is no convenient way to zip two streams, the solution ended up being uglier than I expected.

The task is to take lines of input, in the form a0 a1 a2 … an | b0 b1 b2 … bn, where the ai and bi are integers, and output the products a0b0 a1b1 a2b2 … anbn.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;

public class StreamMultiplier {
    public static IntStream multiply(IntStream aStream, IntStream bStream) {
        PrimitiveIterator.OfInt a = aStream.iterator(),
                                b = bStream.iterator();
        PrimitiveIterator.OfInt product = new PrimitiveIterator.OfInt() {
            public boolean hasNext() { return a.hasNext() &amp;&amp; b.hasNext(); }
            public int nextInt() { return a.next() * b.next(); }
        };
        return StreamSupport.intStream(
            Spliterators.spliteratorUnknownSize(product, Spliterator.ORDERED),
            false
        );
    }

    public static IntStream toIntStream(String spaceDelimitedInts) {
        return Arrays.stream(spaceDelimitedInts.trim().split("\\s+"))
                     .mapToInt(Integer::parseInt);
    }

    public static void main(String[] args) throws FileNotFoundException {
        Scanner input = (args.length &gt; 0) ? new Scanner(new File(args[0]))
                                          : new Scanner(System.in);

        while (input.hasNextLine()) {
            String[] halves = input.nextLine().split("\\|", 2);
            System.out.println(
                multiply(toIntStream(halves[0]), toIntStream(halves[1]))
                .mapToObj(String::valueOf)
                .collect(Collectors.joining(" "))
            );
        }
    }
}


Is this use of Spliterators correct, and can it be improved?
Streams are not designed to naturally fit every computational situation in Java. As you have found, you have needed to perform a number of compound/stream/Iterator/array state changes.

Your data starts as a compound structure in a single file
you scan that using a Scanner, using the Scanner's next structures.
You split the lines in to a 2-element array
you split each element using regex mapped to a parser to get two int arrays
you use the array-stream to convert the two arrays to int streams
you convert the streams to lock-step primitive int iterators
you re-combine the lock-step product result in to another primitive int iterator
you convert that iterator in to a stream
you map the product stream to strings
you collect-and-print the results as a single line.

Note that your work contains far more data state changes than would be necessary using non-stream functionality. The fact that you have to scan the entire line and convert all values to ints means that all the data is in int[] arrays already, and there is no real benefit for any optimization in the streams using short circuiting.
Additionally, your result is not able to be run on a parallel stream because it would not survive in the Iterator stage.
Correlating two active streams is not an operation that is supported using any 'natural' mechanism in Java8.
But, there are ways to do it using non-stream mechanisms, and also much more natural Java8 ways too.
Stream Solution
First up, use a stream for the file IO. Files.lines(...) provides a stream of the lines in a file. Next up, instead of streaming over the values in the source arrays, use a stream of what the two arrays have in common, the indices. Stream over the indices.
By streaming the indices you can process the data in a natural stream way and pull the data by index from the corresponding positions in the sources.
Finally, the product operator should be supplied as an input lambda, and not built in to the stream-iterator-stream translation.
The solution I would use, if forced to use streams for as much as possible, would be:
public static void main(String[] args) throws IOException {
    try (Stream&lt;String&gt; lineStream = args.length &gt; 0 
            ? Files.lines(Paths.get(args[0]), StandardCharsets.UTF_8)
            : new BufferedReader(new InputStreamReader(System.in)).lines()) {

        lineStream.map(line -&gt; processLineWithOperator(line, (a, b) -&gt; a * b))
            .forEach(outLine -&gt; System.out.println(outLine));

    }
}

private static String processLineWithOperator(String line, IntBinaryOperator operator) {
    String[] halves = line.split(&quot;\\|&quot;);
    int[] halfA = toInts(halves[0]);
    int[] halfB = toInts(halves[1]);
    
    return IntStream.range(0, halfA.length)
            .map(index -&gt; operator.applyAsInt(halfA[index], halfB[index]))
            .mapToObj(String::valueOf)
            .collect(Collectors.joining(&quot; &quot;));
    
}

private static int[] toInts(String spaceDelimitedInts) {
    return Arrays.stream(spaceDelimitedInts.split(&quot;\\s+&quot;))
              .mapToInt(Integer::parseInt)
              .toArray();
}