<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>collections &#8211; CodePills.com</title>
	<atom:link href="https://codepills.com/tag/collections/feed/" rel="self" type="application/rss+xml" />
	<link>https://codepills.com</link>
	<description>Helping you make a better code</description>
	<lastBuildDate>Thu, 26 May 2022 19:50:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Flattening Stream Collections in Java</title>
		<link>https://codepills.com/flattening-stream-collections-in-java/</link>
					<comments>https://codepills.com/flattening-stream-collections-in-java/#respond</comments>
		
		<dc:creator><![CDATA[Andrej Buday]]></dc:creator>
		<pubDate>Tue, 01 Mar 2022 15:24:06 +0000</pubDate>
				<category><![CDATA[Language basics]]></category>
		<category><![CDATA[collections]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java 8]]></category>
		<guid isPermaLink="false">https://codepills.com/?p=1289</guid>

					<description><![CDATA[This article is about flattening the list of element list with use of Java 8 stream feature <em>flatMap</em> and <em>forEach</em> <a href="https://codepills.com/flattening-stream-collections-in-java/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>This article is about Java 8 stream feature <em>flatMap</em>. If we have a <code>List&lt;List&lt;Object&gt;&gt;</code>, how can we turn the list of lists into a single list that contains all the elements from the lists in the same streamflow using the features of Java 8?</p>
<p><span id="more-1289"></span></p>
<h2>Introduction</h2>
<p>The answer is simply to use <em>flatMap</em> to flatten the lists of elements into one coherent list of the same elements. <code>flatMap</code> converts lists to streams in a single Stream and then collects the result into a list.</p>
<p>The best explanation will probably show the example of <em>flatMap</em> in action.</p>
<h2>Flattening the List with <em>flatMap</em> &#8211; Simple Example</h2>
<p>Let&#8217;s start with a simple example and continue with a more complex case later in the article. Our simple example will have a list of list with <em>String</em> elements. Each inner list contains a list of <em>String</em> elements which is a tuplet denoting at the first position the level of list and in the second position the overall total position of <em>String</em> element.</p>
<pre><code class="language-java">List&lt;List&lt;String&gt;&gt; nestedList = asList(
    asList("1-1", "1-2", "1-3"),
    asList("2-4", "2-5", "2-6", "2-7", "2-8"),
    asList("3-9", "3-10")
);</code></pre>
<p>We take this simple list above, and we will push it to our simple flattening method <em>flatteningTheListOfLists(List&lt;List&lt;String&gt;&gt; list)</em>.</p>
<pre><code class="language-java">public  List&lt;String&gt; flattenListOfLists(List&lt;List&lt;String&gt;&gt; list) {
    return list.stream()
               .flatMap(Collection::stream)
               .collect(Collectors.toList());
}</code></pre>
<p>As a result, we will get a list with all the <em>String</em> elements in one list.</p>
<pre><code class="language-java">@Test
public void testFlatteningTheListOfLists_simpleScenario() {
     List&lt;String&gt; flattenedList = flattenListOfLists(nestedList);

    assertNotNull(flattenedList);
    assertEquals(10, flattenedList.size());

    for (String element : flattenedList) {
        System.out.print(element);
    }
}</code></pre>
<p><b>Output</b></p>
<pre><code class="language-bash">1-1, 1-2, 1-3, 2-4, 2-5, 2-6, 2-7, 2-8, 3-9, 3-10, </code></pre>
<h2>Flattening the List with <em>flatMap</em> &#8211; Realistic Scenario</h2>
<p>Instead of a simple play with a happy case scenario, hypothetically, let&#8217;s have a more advanced system where we will generate the list of objects directly in the stream. We will have a list of employees with their job position. And we would like to collect all their possible career options for employees above <i>junior engineer</i> level into a single list of all career options across all employees through a department. The resulting list will give us a list of possible combinations of employee promotions above the junior level.</p>
<p>Here is an example of <em>Employee</em> class:</p>
<pre><code class="language-java">public class Employee {

    private Position position;

    public Employee(Position position) {
        this.position = position;
    }

    public int getPosition() {
        return this.position;
    }
}</code></pre>
<p>And here is an example of <em>Employee</em> and <em>Position</em> class:</p>
<pre><code class="language-java">public class Employee {

    private final String name;
    private final Position position;

    public Employee(String name, Position position) {
        this.name = name;
        this.position = position;
    }

    public Position getPosition() {
        return position;
    }

}</code></pre>
<pre><code class="language-java">public enum Position {

    JUNIOR_ENGINEER(1),
    SENIOR_ENGINEER(2),
    SOFTWARE_ARCHITECT(3),
    ENGINEERING_MANAGER(4);

    private final int level;

    Position(int level) {
        this.level = level;
    }

    public int getLevel() {
        return this.level;
    }
}</code></pre>
<p>In order to get the list of all possible career options for all employees above <i>junior level</i> we would create for example something like <code>getAllCareerOptionsAboveJunior(List&lt;Employee&gt; employees)</code> where class <em>employee</em> property is a list of employees of <em>Employee</em> class. <code>getAllCareerOptionsAboveJunior(List&lt;Employee&gt; employees)</code> method will go through all the employees, filter employees from the list with level above junior level and create a list of possible career options for that specific employee. All the career options should be than pushed to <code>List</code> and outputted from stream to <code>List</code> collector.</p>
<pre><code class="language-java">public List&lt;Position&gt; getAllCareerOptionsAboveJunior(List&lt;Employee&gt; employees) {
    return employees.stream()
                    .filter(employee -> employee.getPosition().getLevel() > Position.JUNIOR_ENGINEER.getLevel())
                    .map(employee -> createPossibleCareerOptions(employee.getPosition().getLevel())) // This is bad practice and will not work
                    .collect(Collectors.toList());
}</code></pre>
<p>Example of <i>createPossibleCareerOptions()</i>:</p>
<pre><code class="language-java">public List&lt;Position&gt; createPossibleCareerOptions(int level) {
    return Arrays.stream(Position.values())
                 .filter(position -> position.getLevel() > level)
                 .collect(Collectors.toList());
}</code></pre>
<p>As we can see above, we mapped an employee to the list of her/his career options. But we want to collect list of all possibilities, not list of lists. Therefore, the code above does not work while stream <code>map</code> function maps <code>employee</code> instance into the list, but stream collector can not collect list of position list into the single list.</p>
<p>To make this code work, we need to introduce a consequent function in a stream that will flatten the list&#8217;s mapping into one stream. We need to place <code>flatMap</code> function for flattening the stream of list of positions into single steam positions for our Java stream.</p>
<pre><code class="language-java">public List&lt;Position&gt; getAllCareerOptionsAboveJunior(List&lt;Employee&gt; employees) {
    return employees.stream()
                    .filter(employee -> employee.getPosition().getLevel() > Position.JUNIOR_ENGINEER.getLevel())
                    .map(employee -> createPossibleCareerOptions(employee.getPosition().getLevel()))
                    .flatMap(List::stream) // I need to flatten list streams into one stream
                    .collect(Collectors.toList());
}</code></pre>
<p>Finally, let&#8217;s put all parts together and try the solution on the list of employees.</p>
<pre><code class="language-java">List&lt;Employee&gt; employees = asList(
        new Employee("Mark", Position.JUNIOR_ENGINEER),
        new Employee("Thomas", Position.SENIOR_ENGINEER),
        new Employee("Janet", Position.SOFTWARE_ARCHITECT),
        new Employee("Percy", Position.ENGINEERING_MANAGER)
);</code></pre>
<p>We can test the result with the test written below:</p>
<pre><code class="language-java">@Test
public void testFlatteningTheListOfLists_realisticScenario() {
    List&lt;Position&gt; allPossiblePromotions = getAllCareerOptionsAboveJunior(employees);

    assertNotNull(allPossiblePromotions);
    assertEquals(3, allPossiblePromotions.size());

    for (Position position : allPossiblePromotions) {
        System.out.print(position + ", ");
    }
}</code></pre>
<p><b>Output</b></p>
<pre><code class="language-bash">SOFTWARE_ARCHITECT, ENGINEERING_MANAGER, ENGINEERING_MANAGER, </code></pre>
<p><b>Note</b> : If you have better idea for <code>Map</code> sorting, let me know in comments below.</p>
<h2>Flattening the <em>List</em> With <em>forEach</em></h2>
<p>To flatten this nested collection into a list of the same elements, we can also use <em>forEach</em> together with a Java 8 method reference. However, the solution with <em>forEach</em> might be discouraged by some developers as it needs to create a new reference on the list with results before it returns the complete results. Thus, creating the result variable will make the code more cumbersome and brittle. And while it might be suitable for small lists and simple applications, it brings pointlessly more complexity with its wrapping code for more complex scenarios as described above. On the contrary, it provides no advantage in the form of, for example, code readability.</p>
<p>Neither to say, let&#8217;s take a look at the option of flattening the stream of element&#8217;s list with the help of <em>forEach</em> method.</p>
<pre><code class="language-java">public List&lt;String&gt; useOfForEach(Stream&lt;List&lt;String&gt;&gt; streamOfLists) {
    List&lt;String&gt; result = new ArrayList<>();
    streamOfLists.forEach(result::addAll);
    return result;
}</code></pre>
<p>If we use the same list of simple <em>String</em> elements as for happy case scenario with <em>flatMap</em> we will get the same results.</p>
<h2>Conclusion</h2>
<p>We have seen in this article how to use a Java 8 Stream method <em>flatMap</em> first on a simple example and then on a more realistic scenario. We have also seen the option of flattening the stream with <em>forEach</em>. However, use of <em>forEach</em> might be discouraged on more realistic scenario when used on stream of <i>Objects</i> which generates the lists.</p>
<p>Did you find use of <em>flatMap</em> hard? Do you have your trick or you know another way <u>how to use <em>flatMap</em></u>? Let us know in the comments below the article. We would like to hear your ideas and stories.</p>
<p>As always, you can find all our examples on our <a href="https://github.com/codekopf/tutorials-jvm/tree/master/java-basics/java8/" title="Tutorial JVM - Java Basics - Java 8" target="_blank" rel="nofollow noopener">GitHub project</a>!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codepills.com/flattening-stream-collections-in-java/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
