Довольно просто создать решение, которое перебирает декартово произведение и вызывает созданную пользователем функцию вместо построения их списка. Таким образом, полный продукт никогда не будет в памяти. Если вы предпочитаете сохранить результат в файле, вы также можете сделать это, просто предоставив функцию, которая записывает в файл.
<T> void cartesianProduct(List<List<T>> items, Consumer<List<T>> consumer) {
recurse(items, consumer, new ArrayList<>());
}
<T> void recurse(List<List<T>> items, Consumer<List<T>> consumer, List<T> prefix) {
if (items.isEmpty()) {
consumer.accept(prefix);
} else {
List<T> first = items.get(0);
List<List<T>> rest = items.subList(1, items.size());
for (T item : first) {
prefix.add(item);
recurse(rest, consumer, prefix);
prefix.remove(prefix.size() - 1);
}
}
}
Например, это печатает декартово произведение в System.out:
cartesianProduct(List.of(
List.of("1", "2"), List.of("A", "B"), List.of("!", "@")
), System.out::println);