Build a flat List from a Tree structure in Java I have a Tree structure represented by a List, which I want to get it flattened.

I wrote the function below:

List&lt;Entry&gt; flatTree(List&lt;Entry&gt; toFlat, List&lt;Entry&gt; destination) {
    for (Entry entry : toFlat) {
        if (CollectionUtils.isNotEmpty(entry.getEntries())) {
            this.flatTree(entry.getEntries(), destination);
        } else {
            destination.add(entry);
        }
    }
    return destination;
}


used in this way:

List&lt;Entry&gt; flattenedEntries = this.flatTree(entries, new ArrayList&lt;&gt;());


with this kind of input (entries):

[
    {
        key: "level1.1",
        entries: [] 
    },
    {
        key: "level1.2",
        entries: [
            {
                key: "level2.1",
                entries: [] 
            }
        ]   
    },
    {
        key: "level1.3",
        entries: [
            {
                key: "level2.2",
                entries: [] 
            },
            {
                key: "level2.3",
                entries: [
                    {
                        key: "level3.1",
                        entries: [] 
                    }
                ]   
            }
        ]   
    }
]


What I'm going to achieve is to have a list containing only objects with keys: level1.1, level2.1, level2.2, level3.1 or rather, all the elements that has no sub elements entries.

Each object has just 2 properties inside: key and entries.

It works, but I would like to avoid the side effect on the List&lt;Entry&gt; destination. Is there a better way to write it?
To answer the question from the comment on RoToRa's answer:


  Thanks! I wonder if there is any way to do this by using, for example, just the Java 8 Stream API or something similar, to have it in just one line of code.


Using the Java Stream API

Assuming the following Entry class:

public class Entry {
   final String key;
   final List&lt;Entry&gt; entries = new ArrayList&lt;&gt;();

   Entry(String _key, Entry ...children) {
      key = _key;
      entries.addAll(Arrays.asList(children));
   }

   public List&lt;Entry&gt; getEntries() {
      return Collections.unmodifiableList(entries);
   }

   public String toString() {
      return key;
   }
}


We can build up the example input with:

List&lt;Entry&gt; top = new ArrayList&lt;&gt;();
top.add(new Entry("level1.1"));
top.add(new Entry("level1.2", new Entry("level2.1")));
top.add(new Entry("level1.3", new Entry("level2.2"), new Entry("level2.3", new Entry("level3.1"))));


From @RoToRa's answer, we'll borrow these method signatures:

public static List&lt;Entry&gt; flatTree(List&lt;Entry&gt; toFlat) {
   return flatTree(toFlat, ArrayList::new);
}

public static List&lt;Entry&gt; flatTree(List&lt;Entry&gt; toFlat, Supplier&lt;List&lt;Entry&gt;&gt; listSupplier) {


Now, to flatten with the Stream API, (the requested "one line of code"), we'd want to write something like:

   return toFlat.stream().flatMap(Entry::leaves)
                         .collect(Collectors.toCollection(listSupplier));
}


So, we'll need to define Entry::leaves to extract only the leaves from our tree:

public static Stream&lt;Entry&gt; leaves(Entry entry) {
   if (entry.getEntries().size() &gt; 0)
      return entry.getEntries().stream().flatMap(Entry::leaves);
   else
      return Stream.of(entry);
}


And on the sample data:

jshell&gt; System.out.println(Entry.flatTree(top));
[level1.1, level2.1, level2.2, level3.1]

jshell&gt;