#184 Fluent interface pattern, added uml, adjusted style, added pattern description

This commit is contained in:
Hannes Pernpeintner 2015-09-07 13:25:26 +02:00
parent ee47ae021a
commit fb13ddc5d6
11 changed files with 727 additions and 535 deletions

4
faq.md
View File

@ -61,3 +61,7 @@ As for performance and scalability, pools can become bottlenecks, if all the
pooled objects are in use and more clients need them, threads will become pooled objects are in use and more clients need them, threads will become
blocked waiting for available object from the pool. This is not the case with blocked waiting for available object from the pool. This is not the case with
Flyweight. Flyweight.
### Q7: What are the differences between FluentInterface and Builder patterns? {#Q7}
Fluent interfaces are sometimes confused with the Builder pattern, because they share method chaining and a fluent usage. However, fluent interfaces are not primarily used to create shared (mutable) objects, but to configure complex objects without having to respecify the target object on every property change.

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.fluentinterface.App" project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/App.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="289" y="-8"/>
<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.fluentinterface.fluentiterable.simple.SimpleFluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="450" y="430"/>
<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.fluentinterface.fluentiterable.lazy.LazyFluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="860" y="391"/>
<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>
<interface id="4" language="java" name="com.iluwatar.fluentinterface.fluentiterable.FluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="794" y="55"/>
<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>
</interface>
<class id="5" language="java" name="com.iluwatar.fluentinterface.fluentiterable.lazy.DecoratingIterator"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="1245" y="391"/>
<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>
<interface id="6" language="java" name="java.lang.Iterable" project="fluentinterface"
file="C:/Program Files/Java/jdk1.8.0/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="793" y="-163"/>
<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>
</interface>
<dependency id="7">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</dependency>
<dependency id="8">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="2"/>
</dependency>
<generalization id="9">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="6"/>
</generalization>
<realization id="10">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="4"/>
</realization>
<dependency id="11">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</dependency>
<realization id="12">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="4"/>
</realization>
<dependency id="13">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="5"/>
</dependency>
<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>

28
fluentinterface/index.md Normal file
View File

@ -0,0 +1,28 @@
---
layout: pattern
title: Fluent Interface
folder: fluentinterface
permalink: /patterns/fluentinterface/
categories: Architectural
tags: Java
---
**Intent:** A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
![Fluent Interface](./etc/fluentinterface.png "Fluent Interface")
**Applicability:** Use the Fluent Interface pattern when
* you provide an API that would benefit from a DSL-like usage
* you have objects that are difficult to configure or use
**Real world examples:**
* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/)
**Credits**
* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>java-design-patterns</artifactId> <artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId> <groupId>com.iluwatar</groupId>
<version>1.5.0</version> <version>1.6.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,5 +1,6 @@
package com.iluwatar.fluentinterface; package com.iluwatar.fluentinterface;
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable;
@ -9,11 +10,23 @@ import java.util.function.Predicate;
import static java.lang.String.valueOf; import static java.lang.String.valueOf;
/**
* Fluent interface pattern is useful when you want to provide an easy readable, flowing API. Those
* interfaces tend to mimic domain specific languages, so they can nearly be read as human
* languages.
* <p>
* In this example two implementations of a {@link FluentIterable} interface are given. The
* SimpleFluentIterable evaluates eagerly and would be too costly for real world applications. The
* LazyFluentIterable is evaluated on termination. Their usage is demonstrated with a simple number
* list that is filtered, transformed and collected. The result is printed afterwards.
* <p>
*/
public class App { public class App {
public static void main(String[] args) { public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>() {{ List<Integer> integerList = new ArrayList<Integer>() {
{
add(1); add(1);
add(-61); add(-61);
add(14); add(14);
@ -31,56 +44,59 @@ public class App {
add(2); add(2);
add(-68); add(-68);
add(45); add(45);
}}; }
};
prettyPrint("The initial list contains: ", integerList); prettyPrint("The initial list contains: ", integerList);
List<Integer> firstFiveNegatives = SimpleFluentIterable.from(integerList) List<Integer> firstFiveNegatives =
.filter(negatives()) SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).first(3).asList();
.first(3)
.asList();
prettyPrint("The first three negative values are: ", firstFiveNegatives); prettyPrint("The first three negative values are: ", firstFiveNegatives);
List<Integer> lastTwoPositives = SimpleFluentIterable.from(integerList) List<Integer> lastTwoPositives =
.filter(positives()) SimpleFluentIterable.fromCopyOf(integerList).filter(positives()).last(2).asList();
.last(2)
.asList();
prettyPrint("The last two positive values are: ", lastTwoPositives); prettyPrint("The last two positive values are: ", lastTwoPositives);
SimpleFluentIterable.from(integerList) SimpleFluentIterable
.filter(number -> number%2 == 0) .fromCopyOf(integerList)
.filter(number -> number % 2 == 0)
.first() .first()
.ifPresent(evenNumber -> System.out.println(String.format("The first even number is: %d", evenNumber))); .ifPresent(
evenNumber -> System.out.println(String.format("The first even number is: %d",
evenNumber)));
List<String> transformedList = SimpleFluentIterable.from(integerList) List<String> transformedList =
.filter(negatives()) SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).map(transformToString())
.map(transformToString())
.asList(); .asList();
prettyPrint("A string-mapped list of negative numbers contains: ", transformedList); prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
List<String> lastTwoOfFirstFourStringMapped = LazyFluentIterable.from(integerList) List<String> lastTwoOfFirstFourStringMapped =
.filter(positives()) LazyFluentIterable.from(integerList).filter(positives()).first(4).last(2)
.first(4) .map(number -> "String[" + String.valueOf(number) + "]").asList();
.last(2) prettyPrint(
.map(number -> "String[" + String.valueOf(number) + "]") "The lazy list contains the last two of the first four positive numbers mapped to Strings: ",
.asList(); lastTwoOfFirstFourStringMapped);
prettyPrint("The lazy list contains the last two of the first four positive numbers mapped to Strings: ", lastTwoOfFirstFourStringMapped);
LazyFluentIterable.from(integerList) LazyFluentIterable
.from(integerList)
.filter(negatives()) .filter(negatives())
.first(2) .first(2)
.last() .last()
.ifPresent(lastOfFirstTwo -> System.out.println(String.format("The last of the first two negatives is: %d", lastOfFirstTwo))); .ifPresent(
lastOfFirstTwo -> System.out.println(String.format(
"The last of the first two negatives is: %d", lastOfFirstTwo)));
} }
private static Function<Integer, String> transformToString() { private static Function<Integer, String> transformToString() {
return integer -> "String[" + valueOf(integer) + "]"; return integer -> "String[" + valueOf(integer) + "]";
} }
private static Predicate<? super Integer> negatives() { private static Predicate<? super Integer> negatives() {
return integer -> (integer < 0); return integer -> (integer < 0);
} }
private static Predicate<? super Integer> positives() { private static Predicate<? super Integer> positives() {
return integer -> (integer > 0); return integer -> (integer > 0);
} }
@ -88,11 +104,13 @@ public class App {
private static <TYPE> void prettyPrint(String prefix, Iterable<TYPE> iterable) { private static <TYPE> void prettyPrint(String prefix, Iterable<TYPE> iterable) {
prettyPrint(", ", prefix, ".", iterable); prettyPrint(", ", prefix, ".", iterable);
} }
private static <TYPE> void prettyPrint(String prefix, String suffix, Iterable<TYPE> iterable) { private static <TYPE> void prettyPrint(String prefix, String suffix, Iterable<TYPE> iterable) {
prettyPrint(", ", prefix, suffix, iterable); prettyPrint(", ", prefix, suffix, iterable);
} }
private static <TYPE> void prettyPrint(String delimiter, String prefix, String suffix, Iterable<TYPE> iterable) { private static <TYPE> void prettyPrint(String delimiter, String prefix, String suffix,
Iterable<TYPE> iterable) {
StringJoiner joiner = new StringJoiner(delimiter, prefix, "."); StringJoiner joiner = new StringJoiner(delimiter, prefix, ".");
Iterator<TYPE> iterator = iterable.iterator(); Iterator<TYPE> iterator = iterable.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {

View File

@ -8,49 +8,56 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
* The FluentIterable is a more convenient implementation of the common iterable interface based * The FluentIterable is a more convenient implementation of the common iterable interface based on
* on the fluent interface design pattern. * the fluent interface design pattern. This interface defines common operations, but doesn't aim to
* This interface defines common operations, but * be complete. It was inspired by Guava's com.google.common.collect.FluentIterable.
* doesn't aim to be complete. It was inspired by Guava's com.google.common.collect.FluentIterable. *
* @param <TYPE> is the class of objects the iterable contains * @param <TYPE> is the class of objects the iterable contains
*/ */
public interface FluentIterable<TYPE> extends Iterable<TYPE> { public interface FluentIterable<TYPE> extends Iterable<TYPE> {
/** /**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy the predicate. * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* @param predicate the condition to test with for the filtering. If the test * the predicate.
* is negative, the tested object is removed by the iterator. *
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return a filtered FluentIterable * @return a filtered FluentIterable
*/ */
FluentIterable<TYPE> filter(Predicate<? super TYPE> predicate); FluentIterable<TYPE> filter(Predicate<? super TYPE> predicate);
/** /**
* Returns an Optional containing the first element of this iterable if present, * Returns an Optional containing the first element of this iterable if present, else returns
* else returns Optional.empty(). * Optional.empty().
*
* @return the first element after the iteration is evaluated * @return the first element after the iteration is evaluated
*/ */
Optional<TYPE> first(); Optional<TYPE> first();
/** /**
* Evaluates the iteration and leaves only the count first elements. * Evaluates the iteration and leaves only the count first elements.
*
* @return the first count elements as an Iterable * @return the first count elements as an Iterable
*/ */
FluentIterable<TYPE> first(int count); FluentIterable<TYPE> first(int count);
/** /**
* Evaluates the iteration and returns the last element. This is a terminating operation. * Evaluates the iteration and returns the last element. This is a terminating operation.
*
* @return the last element after the iteration is evaluated * @return the last element after the iteration is evaluated
*/ */
Optional<TYPE> last(); Optional<TYPE> last();
/** /**
* Evaluates the iteration and leaves only the count last elements. * Evaluates the iteration and leaves only the count last elements.
*
* @return the last counts elements as an Iterable * @return the last counts elements as an Iterable
*/ */
FluentIterable<TYPE> last(int count); FluentIterable<TYPE> last(int count);
/** /**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE. * Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE * @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation * @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type * @return a new FluentIterable of the new type
@ -59,12 +66,14 @@ public interface FluentIterable<TYPE> extends Iterable<TYPE> {
/** /**
* Returns the contents of this Iterable as a List. * Returns the contents of this Iterable as a List.
*
* @return a List representation of this Iterable * @return a List representation of this Iterable
*/ */
List<TYPE> asList(); List<TYPE> asList();
/** /**
* Utility method that iterates over iterable and adds the contents to a list. * Utility method that iterates over iterable and adds the contents to a list.
*
* @param iterable the iterable to collect * @param iterable the iterable to collect
* @param <TYPE> the type of the objects to iterate * @param <TYPE> the type of the objects to iterate
* @return a list with all objects of the given iterator * @return a list with all objects of the given iterator

View File

@ -3,8 +3,9 @@ package com.iluwatar.fluentinterface.fluentiterable.lazy;
import java.util.Iterator; import java.util.Iterator;
/** /**
* This class is used to realize LazyFluentIterables. It decorates * This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
* a given iterator. Does not support consecutive hasNext() calls. * support consecutive hasNext() calls.
*
* @param <TYPE> * @param <TYPE>
*/ */
public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> { public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
@ -15,6 +16,7 @@ public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
/** /**
* Creates an iterator that decorates the given iterator. * Creates an iterator that decorates the given iterator.
*
* @param fromIterator * @param fromIterator
*/ */
public DecoratingIterator(Iterator<TYPE> fromIterator) { public DecoratingIterator(Iterator<TYPE> fromIterator) {
@ -23,6 +25,7 @@ public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
/** /**
* Precomputes and saves the next element of the Iterable. null is considered as end of data. * Precomputes and saves the next element of the Iterable. null is considered as end of data.
*
* @return true if a next element is available * @return true if a next element is available
*/ */
@Override @Override
@ -33,6 +36,7 @@ public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
/** /**
* Returns the next element of the Iterable. * Returns the next element of the Iterable.
*
* @return the next element of the Iterable, or null if not present. * @return the next element of the Iterable, or null if not present.
*/ */
@Override @Override
@ -47,8 +51,9 @@ public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
} }
/** /**
* Computes the next object of the Iterable. Can be implemented to * Computes the next object of the Iterable. Can be implemented to realize custom behaviour for an
* realize custom behaviour for an iteration process. null is considered as end of data. * iteration process. null is considered as end of data.
*
* @return the next element of the Iterable. * @return the next element of the Iterable.
*/ */
public abstract TYPE computeNext(); public abstract TYPE computeNext();

View File

@ -11,8 +11,9 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
* This is a lazy implementation of the FluentIterable interface. It evaluates * This is a lazy implementation of the FluentIterable interface. It evaluates all chained
* all chained operations when a terminating operation is applied. * operations when a terminating operation is applied.
*
* @param <TYPE> the type of the objects the iteration is about * @param <TYPE> the type of the objects the iteration is about
*/ */
public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> { public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
@ -20,8 +21,8 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
private final Iterable<TYPE> iterable; private final Iterable<TYPE> iterable;
/** /**
* This constructor creates a new LazyFluentIterable. It wraps the * This constructor creates a new LazyFluentIterable. It wraps the given iterable.
* given iterable. *
* @param iterable the iterable this FluentIterable works on. * @param iterable the iterable this FluentIterable works on.
*/ */
protected LazyFluentIterable(Iterable<TYPE> iterable) { protected LazyFluentIterable(Iterable<TYPE> iterable) {
@ -29,17 +30,18 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
} }
/** /**
* This constructor can be used to implement anonymous subclasses * This constructor can be used to implement anonymous subclasses of the LazyFluentIterable.
* of the LazyFluentIterable.
*/ */
protected LazyFluentIterable() { protected LazyFluentIterable() {
iterable = this; iterable = this;
} }
/** /**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy the predicate. * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* @param predicate the condition to test with for the filtering. If the test * the predicate.
* is negative, the tested object is removed by the iterator. *
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return a new FluentIterable object that decorates the source iterable * @return a new FluentIterable object that decorates the source iterable
*/ */
@Override @Override
@ -50,9 +52,9 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
return new DecoratingIterator<TYPE>(iterable.iterator()) { return new DecoratingIterator<TYPE>(iterable.iterator()) {
@Override @Override
public TYPE computeNext() { public TYPE computeNext() {
while(fromIterator.hasNext()) { while (fromIterator.hasNext()) {
TYPE candidate = fromIterator.next(); TYPE candidate = fromIterator.next();
if(!predicate.test(candidate)) { if (!predicate.test(candidate)) {
continue; continue;
} }
return candidate; return candidate;
@ -67,6 +69,7 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the iteration. Is a terminating operation. * Can be used to collect objects from the iteration. Is a terminating operation.
*
* @return an Optional containing the first object of this Iterable * @return an Optional containing the first object of this Iterable
*/ */
@Override @Override
@ -77,8 +80,10 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the iteration. * Can be used to collect objects from the iteration.
*
* @param count defines the number of objects to return * @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' first objects. * @return the same FluentIterable with a collection decimated to a maximum of 'count' first
* objects.
*/ */
@Override @Override
public FluentIterable<TYPE> first(int count) { public FluentIterable<TYPE> first(int count) {
@ -90,8 +95,8 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
@Override @Override
public TYPE computeNext() { public TYPE computeNext() {
if(currentIndex < count) { if (currentIndex < count) {
if(fromIterator.hasNext()) { if (fromIterator.hasNext()) {
TYPE candidate = fromIterator.next(); TYPE candidate = fromIterator.next();
currentIndex++; currentIndex++;
return candidate; return candidate;
@ -106,6 +111,7 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the iteration. Is a terminating operation. * Can be used to collect objects from the iteration. Is a terminating operation.
*
* @return an Optional containing the last object of this Iterable * @return an Optional containing the last object of this Iterable
*/ */
@Override @Override
@ -115,19 +121,22 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
} }
/** /**
* Can be used to collect objects from the Iterable. Is a terminating operation. * Can be used to collect objects from the Iterable. Is a terminating operation. This operation is
* This operation is memory intensive, because the contents of this Iterable * memory intensive, because the contents of this Iterable are collected into a List, when the
* are collected into a List, when the next object is requested. * next object is requested.
*
* @param count defines the number of objects to return * @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' last objects * @return the same FluentIterable with a collection decimated to a maximum of 'count' last
* objects
*/ */
@Override @Override
public FluentIterable<TYPE> last(int count) {return new LazyFluentIterable<TYPE>() { public FluentIterable<TYPE> last(int count) {
return new LazyFluentIterable<TYPE>() {
@Override @Override
public Iterator<TYPE> iterator() { public Iterator<TYPE> iterator() {
return new DecoratingIterator<TYPE>(iterable.iterator()) { return new DecoratingIterator<TYPE>(iterable.iterator()) {
public int stopIndex; private int stopIndex;
public int totalElementsCount; private int totalElementsCount;
private List<TYPE> list; private List<TYPE> list;
private int currentIndex = 0; private int currentIndex = 0;
@ -136,21 +145,21 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
initialize(); initialize();
TYPE candidate = null; TYPE candidate = null;
while(currentIndex < stopIndex && fromIterator.hasNext()) { while (currentIndex < stopIndex && fromIterator.hasNext()) {
currentIndex++; currentIndex++;
fromIterator.next(); fromIterator.next();
} }
if(currentIndex >= stopIndex && fromIterator.hasNext()) { if (currentIndex >= stopIndex && fromIterator.hasNext()) {
candidate = fromIterator.next(); candidate = fromIterator.next();
} }
return candidate; return candidate;
} }
private void initialize() { private void initialize() {
if(list == null) { if (list == null) {
list = new ArrayList<>(); list = new ArrayList<>();
Iterator<TYPE> newIterator = iterable.iterator(); Iterator<TYPE> newIterator = iterable.iterator();
while(newIterator.hasNext()) { while (newIterator.hasNext()) {
list.add(newIterator.next()); list.add(newIterator.next());
} }
@ -165,6 +174,7 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE. * Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE * @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation * @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type * @return a new FluentIterable of the new type
@ -176,9 +186,10 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
public Iterator<NEW_TYPE> iterator() { public Iterator<NEW_TYPE> iterator() {
return new DecoratingIterator<NEW_TYPE>(null) { return new DecoratingIterator<NEW_TYPE>(null) {
Iterator<TYPE> oldTypeIterator = iterable.iterator(); Iterator<TYPE> oldTypeIterator = iterable.iterator();
@Override @Override
public NEW_TYPE computeNext() { public NEW_TYPE computeNext() {
while(oldTypeIterator.hasNext()) { while (oldTypeIterator.hasNext()) {
TYPE candidate = oldTypeIterator.next(); TYPE candidate = oldTypeIterator.next();
return function.apply(candidate); return function.apply(candidate);
} }
@ -191,6 +202,7 @@ public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Collects all remaining objects of this iteration into a list. * Collects all remaining objects of this iteration into a list.
*
* @return a list with all remaining objects of this iteration * @return a list with all remaining objects of this iteration
*/ */
@Override @Override

View File

@ -8,9 +8,9 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
* This is a simple implementation of the FluentIterable interface. It evaluates * This is a simple implementation of the FluentIterable interface. It evaluates all chained
* all chained operations eagerly. * operations eagerly. This implementation would be costly to be utilized in real applications.
* This implementation would be costly to be utilized in real applications. *
* @param <TYPE> the type of the objects the iteration is about * @param <TYPE> the type of the objects the iteration is about
*/ */
public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> { public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
@ -19,17 +19,19 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* This constructor creates a copy of a given iterable's contents. * This constructor creates a copy of a given iterable's contents.
*
* @param iterable the iterable this interface copies to work on. * @param iterable the iterable this interface copies to work on.
*/ */
protected SimpleFluentIterable(Iterable<TYPE> iterable) { protected SimpleFluentIterable(Iterable<TYPE> iterable) {
List<TYPE> copy = FluentIterable.copyToList(iterable); this.iterable = iterable;
this.iterable = copy;
} }
/** /**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy the predicate. * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* @param predicate the condition to test with for the filtering. If the test * the predicate.
* is negative, the tested object is removed by the iterator. *
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return the same FluentIterable with a filtered collection * @return the same FluentIterable with a filtered collection
*/ */
@Override @Override
@ -37,7 +39,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
Iterator<TYPE> iterator = iterator(); Iterator<TYPE> iterator = iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
TYPE nextElement = iterator.next(); TYPE nextElement = iterator.next();
if(!predicate.test(nextElement)) { if (!predicate.test(nextElement)) {
iterator.remove(); iterator.remove();
} }
} }
@ -46,6 +48,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the Iterable. Is a terminating operation. * Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @return an option of the first object of the Iterable * @return an option of the first object of the Iterable
*/ */
@Override @Override
@ -56,8 +59,10 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the Iterable. Is a terminating operation. * Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @param count defines the number of objects to return * @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' first objects. * @return the same FluentIterable with a collection decimated to a maximum of 'count' first
* objects.
*/ */
@Override @Override
public final FluentIterable<TYPE> first(int count) { public final FluentIterable<TYPE> first(int count) {
@ -65,7 +70,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
int currentCount = 0; int currentCount = 0;
while (iterator.hasNext()) { while (iterator.hasNext()) {
iterator.next(); iterator.next();
if(currentCount >= count) { if (currentCount >= count) {
iterator.remove(); iterator.remove();
} }
currentCount++; currentCount++;
@ -75,12 +80,13 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the Iterable. Is a terminating operation. * Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @return an option of the last object of the Iterable * @return an option of the last object of the Iterable
*/ */
@Override @Override
public final Optional<TYPE> last() { public final Optional<TYPE> last() {
List<TYPE> list = last(1).asList(); List<TYPE> list = last(1).asList();
if(list.isEmpty()) { if (list.isEmpty()) {
return Optional.empty(); return Optional.empty();
} }
return Optional.of(list.get(0)); return Optional.of(list.get(0));
@ -88,8 +94,10 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Can be used to collect objects from the Iterable. Is a terminating operation. * Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @param count defines the number of objects to return * @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' last objects * @return the same FluentIterable with a collection decimated to a maximum of 'count' last
* objects
*/ */
@Override @Override
public final FluentIterable<TYPE> last(int count) { public final FluentIterable<TYPE> last(int count) {
@ -98,7 +106,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
int currentIndex = 0; int currentIndex = 0;
while (iterator.hasNext()) { while (iterator.hasNext()) {
iterator.next(); iterator.next();
if(currentIndex < remainingElementsCount - count) { if (currentIndex < remainingElementsCount - count) {
iterator.remove(); iterator.remove();
} }
currentIndex++; currentIndex++;
@ -109,6 +117,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE. * Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE * @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation * @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type * @return a new FluentIterable of the new type
@ -125,6 +134,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Collects all remaining objects of this Iterable into a list. * Collects all remaining objects of this Iterable into a list.
*
* @return a list with all remaining objects of this Iterable * @return a list with all remaining objects of this Iterable
*/ */
@Override @Override
@ -139,6 +149,11 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
return new SimpleFluentIterable<>(iterable); return new SimpleFluentIterable<>(iterable);
} }
public static final <TYPE> FluentIterable<TYPE> fromCopyOf(Iterable<TYPE> iterable) {
List<TYPE> copy = FluentIterable.copyToList(iterable);
return new SimpleFluentIterable<>(copy);
}
@Override @Override
public Iterator<TYPE> iterator() { public Iterator<TYPE> iterator() {
return iterable.iterator(); return iterable.iterator();
@ -161,7 +176,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
public final int getRemainingElementsCount() { public final int getRemainingElementsCount() {
int counter = 0; int counter = 0;
Iterator<TYPE> iterator = iterator(); Iterator<TYPE> iterator = iterator();
while(iterator.hasNext()) { while (iterator.hasNext()) {
iterator.next(); iterator.next();
counter++; counter++;
} }
@ -170,6 +185,7 @@ public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
/** /**
* Collects the remaining objects of the given iterator into a List. * Collects the remaining objects of the given iterator into a List.
*
* @return a new List with the remaining objects. * @return a new List with the remaining objects.
*/ */
public static <TYPE> List<TYPE> toList(Iterator<TYPE> iterator) { public static <TYPE> List<TYPE> toList(Iterator<TYPE> iterator) {