You could use a recursive approach.
At each step, you deal with one list only, "guess" which element to add to the so far solution, and recurse on a "smaller" problem, with one fewer list:
public static <T> void getCombination(List<T>... lists) {
if (lists == null) return;
getCombinations(new ArrayList<T>(), 0, lists);
}
private static <T> void getCombinations(List<T> soFar, int i, List<T> ... lists) {
if (i == lists.length) { //no more lists left:
//do work on soFar, for example:
System.out.println(soFar);
}
else {
for (T t : lists[i]) {
soFar.add(t); //"guess" item
getCombinations(soFar, i+1, lists); //recurse on rest of lists
soFar.remove(soFar.size()-1); //cleanup
}
}
}
Invoke the above with:
public static void main(String args[]) {
List<String> a= Arrays.asList("abc","def");
List<String> b= Arrays.asList("abc","def");
List<String> c=Arrays.asList("abc","def");
List<String> d=Arrays.asList("abc","def");
getCombination(a,b,c,d);
}
and you will get:
[abc, abc, abc, abc]
[abc, abc, abc, def]
[abc, abc, def, abc]
[abc, abc, def, def]
[abc, def, abc, abc]
[abc, def, abc, def]
[abc, def, def, abc]
[abc, def, def, def]
[def, abc, abc, abc]
[def, abc, abc, def]
[def, abc, def, abc]
[def, abc, def, def]
[def, def, abc, abc]
[def, def, abc, def]
[def, def, def, abc]
[def, def, def, def]
This approach can handle any number of such lists, and the lists can be of any size, but be advised that the size of the solution (and running time) is exponential in the number of lists, but that's to be expected, since any solution that will try to path through all combinations will have to go through exponential number of such.