Last active
February 2, 2017 09:48
-
-
Save calvernaz/d60569c344a5c3202981d2ade4811763 to your computer and use it in GitHub Desktop.
Fluent Immutable List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.util.collections; | |
import static com.google.common.collect.FluentIterable.from; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.Set; | |
import java.util.stream.Stream; | |
import org.apache.commons.lang3.builder.EqualsBuilder; | |
import org.apache.commons.lang3.builder.HashCodeBuilder; | |
import com.fasterxml.jackson.annotation.JsonCreator; | |
import com.fasterxml.jackson.annotation.JsonIgnore; | |
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |
import com.fasterxml.jackson.annotation.JsonProperty; | |
import com.fsg.prizebonds.util.executor.Executor; | |
import com.fsg.prizebonds.util.mutation.Mutation; | |
import com.fsg.prizebonds.util.specification.Specification; | |
import com.google.common.base.Function; | |
import com.google.common.base.Optional; | |
import com.google.common.base.Predicate; | |
import com.google.common.base.Predicates; | |
import com.google.common.collect.Collections2; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Iterables; | |
import com.google.common.collect.Sets; | |
@JsonIgnoreProperties(ignoreUnknown = true) | |
public class FluentImmutableList<T> implements Iterable<T> { | |
@JsonProperty("items") | |
protected final ImmutableList<T> items; | |
public static <T> FluentImmutableList<T> emptyList() { | |
return new FluentImmutableList<>(); | |
} | |
public FluentImmutableList(T t) { | |
this.items = ImmutableList.of(t); | |
} | |
public FluentImmutableList(FluentImmutableList<T> items) { | |
this(items.items); | |
} | |
@JsonCreator | |
public FluentImmutableList(@JsonProperty("items") Collection<T> items) { | |
if (items == null) { | |
items = Collections.emptyList(); | |
} | |
this.items = ImmutableList.copyOf(items); | |
} | |
protected FluentImmutableList() { | |
this(new ArrayList<T>()); | |
} | |
public FluentImmutableList(Iterable<T> iterables) { | |
this(ImmutableList.copyOf(iterables)); | |
} | |
@Override | |
public Iterator<T> iterator() { | |
return items.iterator(); | |
} | |
@JsonIgnore | |
public boolean isEmpty() { | |
return items.isEmpty(); | |
} | |
@JsonIgnore | |
public int size() { | |
return items.size(); | |
} | |
@JsonIgnore | |
public Set<T> toSet() { | |
return new HashSet<>(items); | |
} | |
@JsonIgnore | |
public ImmutableList<T> toList() { | |
return items.asList(); | |
} | |
@JsonIgnore | |
public Optional<T> tryPluck(T toMatch) { | |
return from(items).firstMatch(new EqualsMatching<>(toMatch)); | |
} | |
@JsonIgnore | |
public T pluck(T toMatch) { | |
return tryPluck(toMatch).orNull(); | |
} | |
@JsonIgnore | |
public boolean isPresent(T t) { | |
return tryPluck(t).isPresent(); | |
} | |
protected FluentImmutableList<T> differenceWith(FluentImmutableList<T> other) { | |
return new FluentImmutableList<>(Sets.difference(toSet(), other.toSet())); | |
} | |
protected FluentImmutableList<T> unionWith(FluentImmutableList<T> other) { | |
return new FluentImmutableList<>(Sets.union(toSet(), other.toSet())); | |
} | |
protected FluentImmutableList<T> filter(Predicate<T> predicate) { | |
return new FluentImmutableList<>(from(items).filter(predicate) | |
.toList()); | |
} | |
protected FluentImmutableList<T> uniqueHammers() { | |
return new FluentImmutableList<>(toSet()); | |
} | |
protected FluentImmutableList<T> addItem(T t) { | |
if (t == null) return this; | |
ImmutableList<T> newHammers = ImmutableList.<T>builder() | |
.addAll(items) | |
.add(t) | |
.build(); | |
return new FluentImmutableList<>(newHammers); | |
} | |
protected FluentImmutableList<T> removeItem(T t) { | |
if (t == null) return this; | |
Collection<T> filtered = Collections2.filter(items, Predicates.not(Predicates.equalTo(t))); | |
return new FluentImmutableList<>(filtered); | |
} | |
protected Collection<T> removeItems(Collection<T> toRemove) { | |
return Collections2.filter(items, Predicates.not(Predicates.in(toRemove))); | |
} | |
public <Y> ImmutableList<Y> transform(Function<T, Y> function) { | |
return from(items).transform(function) | |
.toList(); | |
} | |
protected FluentImmutableList<T> concat(Iterable<? extends FluentImmutableList<T>> collections) { | |
FluentImmutableList<T> merged = new FluentImmutableList<>(); | |
for (FluentImmutableList<T> collection : collections) { | |
merged = merged.concat(collection); | |
} | |
return merged; | |
} | |
protected FluentImmutableList<T> concat(FluentImmutableList<T> collection) { | |
if (collection == null) return this; | |
return new FluentImmutableList<>(Iterables.concat(this, collection)); | |
} | |
protected FluentImmutableList union(T t) { | |
if (t == null) return this; | |
return this.concat(new FluentImmutableList<>(t)); | |
} | |
@JsonIgnore | |
public FluentImmutableList<T> concat(Collection<T> items) { | |
return concat(new FluentImmutableList<>(items)); | |
} | |
@JsonIgnore | |
public FluentImmutableList<T> mutateUsing(Mutation<T> mutation) { | |
for (T t : items) { | |
mutation.mutate(t); | |
} | |
return this; | |
} | |
@JsonIgnore | |
public FluentImmutableList<T> executeUsing(Executor<T> executor) { | |
for (T t : items) { | |
executor.execute(t); | |
} | |
return this; | |
} | |
@JsonIgnore | |
public T first() { | |
return firstOr(null); | |
} | |
@JsonIgnore | |
public T firstOr(T defaultValue) { | |
return Iterables.getFirst(items, defaultValue); | |
} | |
@JsonIgnore | |
public T last() { | |
return lastOr(null); | |
} | |
@JsonIgnore | |
public T lastOr(T defaultValue) { | |
return Iterables.getLast(items, defaultValue); | |
} | |
@SuppressWarnings("unchecked") | |
@Override | |
public boolean equals(Object obj) { | |
if (obj == null) return false; | |
if (!(obj instanceof FluentImmutableList)) return false; | |
FluentImmutableList<T> rhs = (FluentImmutableList<T>) obj; | |
return new EqualsBuilder().append(items, rhs.items) | |
.isEquals(); | |
} | |
@Override | |
public int hashCode() { | |
return new HashCodeBuilder(3, 11).append(items) | |
.toHashCode(); | |
} | |
@JsonIgnore | |
public Optional<T> firstMatch(Specification<T> spec) { | |
return from(items).firstMatch(spec); | |
} | |
@JsonIgnore | |
public T getAt(int index) { | |
return items.get(index); | |
} | |
@JsonIgnore | |
public T getFirstMatch(Specification<T> spec) { | |
Optional<T> firstMatch = firstMatch(spec); | |
if (!firstMatch.isPresent()) { | |
throw new IllegalStateException("No matching item from given specification"); | |
} | |
return firstMatch.get(); | |
} | |
@JsonIgnore | |
public boolean contains(T t) { | |
if (isEmpty()) return false; | |
return items.contains(t); | |
} | |
@JsonIgnore | |
public boolean containsAll(FluentImmutableList<T> others) { | |
if (isEmpty()) return false; | |
if (others.isEmpty()) return false; | |
return items.containsAll(others.items); | |
} | |
@JsonIgnore | |
public Stream<T> stream() { | |
return items.stream(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment