I did permutations of two [0..4] values. Extending to three/four should be straight forward.
Haskell, do notation version:
do { a <- [0..4]; b <- [0..4]; [(a, b)] }
Haskell, bind version:
[0..4] >>= (\a -> [0..4] >>= (\b -> [(a, b)]))
Scala, for comprehension (just like Haskell's do notation):
for (a <- 0 until 4; b <- 0 until 4) yield (a,b)
Java 8 Stream/Lambda version:
Stream<AbstractMap.SimpleImmutableEntry<Integer, Integer>> s1 = IntStream.rangeClosed(0, 4).boxed().flatMap(a -> IntStream.rangeClosed(0, 4).mapToObj(b -> new AbstractMap.SimpleImmutableEntry<Integer, Integer>(a, b)));
List<AbstractMap.SimpleImmutableEntry<Integer, Integer>> l1 = s1.collect(Collectors.toList());
Clearly, the Java 8 version is far clumsier than the others. The biggest hold ups with Java are the lack of tuples, the primitive/object divide, and then the lack of flatMap syntactic sugar like Haskell's do or Scala's for.
With this type of functional programming exercise, Java 8 is a big step up from Java 7, but far short of Scala or Haskell.
Also, as much as I like this group, I'd recommend stackexchange as a better alternative for this type of focused question with a direct answer.