static <T1, T2, T3, R> Seq<R> zipAll(Seq<? extends T1> s1, Seq<? extends T2> s2, Seq<? extends T3> s3, T1 default1, T2 default2, T3 default3, Function3<? super T1, ? super T2, ? super T3, ? extends R> zipper) {
        final Iterator<? extends T1> it1 = s1.iterator();
        final Iterator<? extends T2> it2 = s2.iterator();
        final Iterator<? extends T3> it3 = s3.iterator();

        class ZipAll implements Iterator<R> {
            
            @Override
            public boolean hasNext() {
                return it1.hasNext() || it2.hasNext() || it3.hasNext();
            }

            @Override
            public R next() {
                boolean b1 = it1.hasNext();
                boolean b2 = it2.hasNext();
                boolean b3 = it3.hasNext();
                
                if (!b1 && !b2 && !b3)
                    throw new NoSuchElementException("next on empty iterator");
                
                return zipper.apply(
                    b1 ? it1.next() : default1,
                    b2 ? it2.next() : default2,
                    b3 ? it3.next() : default3
                );
            }
        }

        return seq(new ZipAll()).onClose(SeqUtils.closeAll(s1, s2, s3));
    }
Zip two streams into one using a {@link BiFunction} to produce resulting values,
when one of streams will end, a default value for that stream will be provided instead -
so the resulting stream will be as long as the longest of the two streams.
<p>
<pre><code>
// ("1:a", "2:x", "3:x")
Seq.zipAll(Seq.of(1, 2, 3), Seq.of("a"), 0, "x", (i, s) -> i + ":" + s)
</code></pre>
jOOL/src/main/java/org/jooq/lambda/Seq.java