Merge pull request #767 from nikhilbarar/collection-pipeline
#564: Collection Pipeline pattern
This commit is contained in:
commit
1698b066f3
30
collection-pipeline/README.md
Normal file
30
collection-pipeline/README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Collection Pipeline
|
||||||
|
folder: collection-pipeline
|
||||||
|
permalink: /patterns/collection-pipeline/
|
||||||
|
categories: Functional
|
||||||
|
tags:
|
||||||
|
- Java
|
||||||
|
- Difficulty-Beginner
|
||||||
|
- Functional
|
||||||
|
---
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
Collection Pipeline introduces Function Composition and Collection Pipeline, two functional-style patterns that you can combine to iterate collections in your code.
|
||||||
|
In functional programming, it's common to sequence complex operations through a series of smaller modular functions or operations. The series is called a composition of functions, or a function composition. When a collection of data flows through a function composition, it becomes a collection pipeline. Function Composition and Collection Pipeline are two design patterns frequently used in functional-style programming.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Applicability
|
||||||
|
Use the Collection Pipeline pattern when
|
||||||
|
|
||||||
|
* When you want to perform a sequence of operations where one operation's collected output is fed into the next
|
||||||
|
* When you use a lot of statements in your code
|
||||||
|
* When you use a lot of loops in your code
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
* [Function composition and the Collection Pipeline pattern](https://www.ibm.com/developerworks/library/j-java8idioms2/index.html)
|
||||||
|
* [Martin Fowler](https://martinfowler.com/articles/collection-pipeline/)
|
||||||
|
* [Java8 Streams](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)
|
BIN
collection-pipeline/etc/collection-pipeline.png
Normal file
BIN
collection-pipeline/etc/collection-pipeline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
98
collection-pipeline/etc/collection-pipeline.ucls
Normal file
98
collection-pipeline/etc/collection-pipeline.ucls
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||||
|
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||||
|
<class id="1" language="java" name="com.iluwatar.collectionpipeline.App" project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/App.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="150" y="100"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<class id="2" language="java" name="com.iluwatar.collectionpipeline.ImperativeProgramming"
|
||||||
|
project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/ImperativeProgramming.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="437" y="109"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<class id="3" language="java" name="com.iluwatar.collectionpipeline.Car" project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="724" y="339"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<class id="4" language="java" name="com.iluwatar.collectionpipeline.CarFactory" project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/CarFactory.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="899" y="91"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<class id="5" language="java" name="com.iluwatar.collectionpipeline.FunctionalProgramming"
|
||||||
|
project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/FunctionalProgramming.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="1187" y="109"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<enumeration id="6" language="java" name="com.iluwatar.collectionpipeline.Category" project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Category.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="486" y="339"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</enumeration>
|
||||||
|
<class id="7" language="java" name="com.iluwatar.collectionpipeline.Person" project="collection-pipeline"
|
||||||
|
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Person.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="723" y="91"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<association id="8">
|
||||||
|
<end type="SOURCE" refId="7" navigable="false">
|
||||||
|
<attribute id="9" name="cars"/>
|
||||||
|
<multiplicity id="10" minimum="0" maximum="2147483647"/>
|
||||||
|
</end>
|
||||||
|
<end type="TARGET" refId="3" navigable="true"/>
|
||||||
|
<display labels="true" multiplicity="true"/>
|
||||||
|
</association>
|
||||||
|
<association id="11">
|
||||||
|
<end type="SOURCE" refId="3" navigable="false">
|
||||||
|
<attribute id="12" name="category"/>
|
||||||
|
<multiplicity id="13" minimum="0" maximum="1"/>
|
||||||
|
</end>
|
||||||
|
<end type="TARGET" refId="6" navigable="true"/>
|
||||||
|
<display labels="true" multiplicity="true"/>
|
||||||
|
</association>
|
||||||
|
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</classifier-display>
|
||||||
|
<association-display labels="true" multiplicity="true"/>
|
||||||
|
</class-diagram>
|
45
collection-pipeline/pom.xml
Normal file
45
collection-pipeline/pom.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.20.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>collection-pipeline</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In imperative-style programming, it is common to use for and while loops for
|
||||||
|
* most kinds of data processing. Function composition is a simple technique
|
||||||
|
* that lets you sequence modular functions to create more complex operations.
|
||||||
|
* When you run data through the sequence, you have a collection pipeline.
|
||||||
|
* Together, the Function Composition and Collection Pipeline patterns enable
|
||||||
|
* you to create sophisticated programs where data flow from upstream to
|
||||||
|
* downstream and is passed through a series of transformations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class App {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program entry point.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
* command line args
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
List<Car> cars = CarFactory.createCars();
|
||||||
|
|
||||||
|
List<String> modelsImperative = ImperativeProgramming.getModelsAfter2000(cars);
|
||||||
|
LOGGER.info(modelsImperative.toString());
|
||||||
|
|
||||||
|
List<String> modelsFunctional = FunctionalProgramming.getModelsAfter2000(cars);
|
||||||
|
LOGGER.info(modelsFunctional.toString());
|
||||||
|
|
||||||
|
Map<Category, List<Car>> groupingByCategoryImperative = ImperativeProgramming.getGroupingOfCarsByCategory(cars);
|
||||||
|
LOGGER.info(groupingByCategoryImperative.toString());
|
||||||
|
|
||||||
|
Map<Category, List<Car>> groupingByCategoryFunctional = FunctionalProgramming.getGroupingOfCarsByCategory(cars);
|
||||||
|
LOGGER.info(groupingByCategoryFunctional.toString());
|
||||||
|
|
||||||
|
Person john = new Person(cars);
|
||||||
|
|
||||||
|
List<Car> sedansOwnedImperative = ImperativeProgramming.getSedanCarsOwnedSortedByDate(Arrays.asList(john));
|
||||||
|
LOGGER.info(sedansOwnedImperative.toString());
|
||||||
|
|
||||||
|
List<Car> sedansOwnedFunctional = FunctionalProgramming.getSedanCarsOwnedSortedByDate(Arrays.asList(john));
|
||||||
|
LOGGER.info(sedansOwnedFunctional.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Car class that has the properties of make, model, year and category.
|
||||||
|
*/
|
||||||
|
public class Car {
|
||||||
|
private String make;
|
||||||
|
private String model;
|
||||||
|
private int year;
|
||||||
|
private Category category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to create an instance of car.
|
||||||
|
* @param make the make of the car
|
||||||
|
* @param model the model of the car
|
||||||
|
* @param yearOfMake the year of built of the car
|
||||||
|
* @param category the {@link Category} of the car
|
||||||
|
*/
|
||||||
|
public Car(String make, String model, int yearOfMake, Category category) {
|
||||||
|
this.make = make;
|
||||||
|
this.model = model;
|
||||||
|
this.year = yearOfMake;
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((category == null) ? 0 : category.hashCode());
|
||||||
|
result = prime * result + ((make == null) ? 0 : make.hashCode());
|
||||||
|
result = prime * result + ((model == null) ? 0 : model.hashCode());
|
||||||
|
result = prime * result + year;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Car other = (Car) obj;
|
||||||
|
if (category != other.category) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (make == null) {
|
||||||
|
if (other.make != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!make.equals(other.make)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (model == null) {
|
||||||
|
if (other.model != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!model.equals(other.model)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (year != other.year) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMake() {
|
||||||
|
return make;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Category getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory class to create a collection of {@link Car} instances.
|
||||||
|
*/
|
||||||
|
public class CarFactory {
|
||||||
|
private CarFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to create a {@link List} of {@link Car} instances.
|
||||||
|
* @return {@link List} of {@link Car}
|
||||||
|
*/
|
||||||
|
public static List<Car> createCars() {
|
||||||
|
return Arrays.asList(new Car("Jeep", "Wrangler", 2011, Category.JEEP),
|
||||||
|
new Car("Jeep", "Comanche", 1990, Category.JEEP),
|
||||||
|
new Car("Dodge", "Avenger", 2010, Category.SEDAN),
|
||||||
|
new Car("Buick", "Cascada", 2016, Category.CONVERTIBLE),
|
||||||
|
new Car("Ford", "Focus", 2012, Category.SEDAN),
|
||||||
|
new Car("Chevrolet", "Geo Metro", 1992, Category.CONVERTIBLE));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum for the category of car
|
||||||
|
*/
|
||||||
|
public enum Category {
|
||||||
|
JEEP, SEDAN, CONVERTIBLE
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterating and sorting with a collection pipeline
|
||||||
|
*
|
||||||
|
* <p>In functional programming, it's common to sequence complex operations through
|
||||||
|
* a series of smaller modular functions or operations. The series is called a
|
||||||
|
* composition of functions, or a function composition. When a collection of
|
||||||
|
* data flows through a function composition, it becomes a collection pipeline.
|
||||||
|
* Function Composition and Collection Pipeline are two design patterns
|
||||||
|
* frequently used in functional-style programming.
|
||||||
|
*
|
||||||
|
* <p>Instead of passing a lambda expression to the map method, we passed the
|
||||||
|
* method reference Car::getModel. Likewise, instead of passing the lambda
|
||||||
|
* expression car -> car.getYear() to the comparing method, we passed the method
|
||||||
|
* reference Car::getYear. Method references are short, concise, and expressive.
|
||||||
|
* It is best to use them wherever possible.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FunctionalProgramming {
|
||||||
|
private FunctionalProgramming() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get models using for collection pipeline.
|
||||||
|
*
|
||||||
|
* @param cars {@link List} of {@link Car} to be used for filtering
|
||||||
|
* @return {@link List} of {@link String} representing models built after year 2000
|
||||||
|
*/
|
||||||
|
public static List<String> getModelsAfter2000(List<Car> cars) {
|
||||||
|
return cars.stream().filter(car -> car.getYear() > 2000)
|
||||||
|
.sorted(Comparator.comparing(Car::getYear))
|
||||||
|
.map(Car::getModel).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to group cars by category using groupingBy
|
||||||
|
*
|
||||||
|
* @param cars {@link List} of {@link Car} to be used for grouping
|
||||||
|
* @return {@link Map} with category as key and cars belonging to that category as value
|
||||||
|
*/
|
||||||
|
public static Map<Category, List<Car>> getGroupingOfCarsByCategory(List<Car> cars) {
|
||||||
|
return cars.stream().collect(Collectors.groupingBy(Car::getCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get all Sedan cars belonging to a group of persons sorted by year of manufacture
|
||||||
|
*
|
||||||
|
* @param persons {@link List} of {@link Person} to be used
|
||||||
|
* @return {@link List} of {@link Car} to belonging to the group
|
||||||
|
*/
|
||||||
|
public static List<Car> getSedanCarsOwnedSortedByDate(List<Person> persons) {
|
||||||
|
return persons.stream().map(Person::getCars).flatMap(List::stream)
|
||||||
|
.filter(car -> Category.SEDAN.equals(car.getCategory()))
|
||||||
|
.sorted(Comparator.comparing(Car::getYear)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imperative-style programming to iterate over the list and get the names of
|
||||||
|
* cars made later than the year 2000. We then sort the models in ascending
|
||||||
|
* order by year.
|
||||||
|
*
|
||||||
|
* <p>As you can see, there's a lot of looping in this code. First, the
|
||||||
|
* getModelsAfter2000UsingFor method takes a list of cars as its parameter. It
|
||||||
|
* extracts or filters out cars made after the year 2000, putting them into a
|
||||||
|
* new list named carsSortedByYear. Next, it sorts that list in ascending order
|
||||||
|
* by year-of-make. Finally, it loops through the list carsSortedByYear to get
|
||||||
|
* the model names and returns them in a list.
|
||||||
|
*
|
||||||
|
* <p>This short example demonstrates what I call the effect of statements. While
|
||||||
|
* functions and methods in general can be used as expressions, the {@link Collections}
|
||||||
|
* sort method doesn't return a result. Because it is used as a statement, it
|
||||||
|
* mutates the list given as argument. Both of the for loops also mutate lists
|
||||||
|
* as they iterate. Being statements, that's just how these elements work. As a
|
||||||
|
* result, the code contains unnecessary garbage variables
|
||||||
|
*/
|
||||||
|
public class ImperativeProgramming {
|
||||||
|
private ImperativeProgramming() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the car models built after year 2000 using for loops.
|
||||||
|
* @param cars {@link List} of {@link Car} to iterate over
|
||||||
|
* @return {@link List} of {@link String} of car models built after year 2000
|
||||||
|
*/
|
||||||
|
public static List<String> getModelsAfter2000(List<Car> cars) {
|
||||||
|
List<Car> carsSortedByYear = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Car car : cars) {
|
||||||
|
if (car.getYear() > 2000) {
|
||||||
|
carsSortedByYear.add(car);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(carsSortedByYear, new Comparator<Car>() {
|
||||||
|
public int compare(Car car1, Car car2) {
|
||||||
|
return new Integer(car1.getYear()).compareTo(car2.getYear());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<String> models = new ArrayList<>();
|
||||||
|
for (Car car : carsSortedByYear) {
|
||||||
|
models.add(car.getModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to group cars by category using for loops
|
||||||
|
*
|
||||||
|
* @param cars {@link List} of {@link Car} to be used for grouping
|
||||||
|
* @return {@link Map} with category as key and cars belonging to that category as value
|
||||||
|
*/
|
||||||
|
public static Map<Category, List<Car>> getGroupingOfCarsByCategory(List<Car> cars) {
|
||||||
|
Map<Category, List<Car>> groupingByCategory = new HashMap<>();
|
||||||
|
for (Car car: cars) {
|
||||||
|
if (groupingByCategory.containsKey(car.getCategory())) {
|
||||||
|
groupingByCategory.get(car.getCategory()).add(car);
|
||||||
|
} else {
|
||||||
|
List<Car> categoryCars = new ArrayList<>();
|
||||||
|
categoryCars.add(car);
|
||||||
|
groupingByCategory.put(car.getCategory(), categoryCars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupingByCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get all Sedan cars belonging to a group of persons sorted by year of manufacture using for loops
|
||||||
|
*
|
||||||
|
* @param persons {@link List} of {@link Person} to be used
|
||||||
|
* @return {@link List} of {@link Car} to belonging to the group
|
||||||
|
*/
|
||||||
|
public static List<Car> getSedanCarsOwnedSortedByDate(List<Person> persons) {
|
||||||
|
List<Car> cars = new ArrayList<>();
|
||||||
|
for (Person person: persons) {
|
||||||
|
cars.addAll(person.getCars());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Car> sedanCars = new ArrayList<>();
|
||||||
|
for (Car car: cars) {
|
||||||
|
if (Category.SEDAN.equals(car.getCategory())) {
|
||||||
|
sedanCars.add(car);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sedanCars.sort(new Comparator<Car>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Car o1, Car o2) {
|
||||||
|
return o1.getYear() - o2.getYear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sedanCars;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Person class that has the list of cars that the person owns and use.
|
||||||
|
*/
|
||||||
|
public class Person {
|
||||||
|
private List<Car> cars;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to create an instance of person.
|
||||||
|
* @param cars the list of cars owned
|
||||||
|
*/
|
||||||
|
public Person(List<Car> cars) {
|
||||||
|
this.cars = cars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Car> getCars() {
|
||||||
|
return cars;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* The MIT License
|
||||||
|
* Copyright (c) 2014 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.iluwatar.collectionpipeline;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that Collection Pipeline methods work as expected.
|
||||||
|
*/
|
||||||
|
public class AppTest {
|
||||||
|
|
||||||
|
private List<Car> cars = CarFactory.createCars();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetModelsAfter2000UsingFor() {
|
||||||
|
List<String> models = ImperativeProgramming.getModelsAfter2000(cars);
|
||||||
|
assertEquals(Arrays.asList("Avenger", "Wrangler", "Focus", "Cascada"), models);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetModelsAfter2000UsingPipeline() {
|
||||||
|
List<String> models = FunctionalProgramming.getModelsAfter2000(cars);
|
||||||
|
assertEquals(Arrays.asList("Avenger", "Wrangler", "Focus", "Cascada"), models);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetGroupingOfCarsByCategory() {
|
||||||
|
Map<Category, List<Car>> modelsExpected = new HashMap<>();
|
||||||
|
modelsExpected.put(Category.CONVERTIBLE, Arrays.asList(new Car("Buick", "Cascada", 2016, Category.CONVERTIBLE),
|
||||||
|
new Car("Chevrolet", "Geo Metro", 1992, Category.CONVERTIBLE)));
|
||||||
|
modelsExpected.put(Category.SEDAN, Arrays.asList(new Car("Dodge", "Avenger", 2010, Category.SEDAN),
|
||||||
|
new Car("Ford", "Focus", 2012, Category.SEDAN)));
|
||||||
|
modelsExpected.put(Category.JEEP, Arrays.asList(new Car("Jeep", "Wrangler", 2011, Category.JEEP),
|
||||||
|
new Car("Jeep", "Comanche", 1990, Category.JEEP)));
|
||||||
|
Map<Category, List<Car>> modelsFunctional = FunctionalProgramming.getGroupingOfCarsByCategory(cars);
|
||||||
|
Map<Category, List<Car>> modelsImperative = ImperativeProgramming.getGroupingOfCarsByCategory(cars);
|
||||||
|
System.out.println("Category " + modelsFunctional);
|
||||||
|
assertEquals(modelsExpected, modelsFunctional);
|
||||||
|
assertEquals(modelsExpected, modelsImperative);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSedanCarsOwnedSortedByDate() {
|
||||||
|
Person john = new Person(cars);
|
||||||
|
List<Car> modelsExpected = Arrays.asList(new Car("Dodge", "Avenger", 2010, Category.SEDAN),
|
||||||
|
new Car("Ford", "Focus", 2012, Category.SEDAN));
|
||||||
|
List<Car> modelsFunctional = FunctionalProgramming.getSedanCarsOwnedSortedByDate(Arrays.asList(john));
|
||||||
|
List<Car> modelsImperative = ImperativeProgramming.getSedanCarsOwnedSortedByDate(Arrays.asList(john));
|
||||||
|
assertEquals(modelsExpected, modelsFunctional);
|
||||||
|
assertEquals(modelsExpected, modelsImperative);
|
||||||
|
}
|
||||||
|
}
|
3
pom.xml
3
pom.xml
@ -162,7 +162,8 @@
|
|||||||
<module>trampoline</module>
|
<module>trampoline</module>
|
||||||
<module>serverless</module>
|
<module>serverless</module>
|
||||||
<module>ambassador</module>
|
<module>ambassador</module>
|
||||||
<module>acyclic-visitor</module>
|
<module>acyclic-visitor</module>
|
||||||
|
<module>collection-pipeline</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user