Hot questions for Collections in Guava

Top 10 Java Open Source / Guava / Collections

A Queue that ensure uniqueness of the elements?

Question: I'm looking for a implementation of java.util.Queue or something in the Google collection who behave like a Queue, but also ensure that each element of the queue is unique. (all further insertion will have no effect)

It's that possible, or will I have to do it by hand?

For now I'm using a Queue, with a LinkedList implementation, and I check the uniqueness before insertion. ( I use a side Map for doing this, add / remove element from the side map before / after the queu ). I don't like it too much.

If it's not in the java.util package, then maybe it's a bad idea?

Answer: How about a LinkedHashSet? Its iterator preserves insertion order, but because it's a Set, its elements are unique.

As its documentation says, Note that insertion order is not affected if an element is re-inserted into the set.

In order to efficiently remove elements from the head of this "queue", go through its iterator:

Iterator<?> i = queue.iterator();
...
Object next = i.next();
i.remove();

Cleanest way to index a Collection by a property of the item's that itself is a collection

Question: I have a List<Foo> and want a guava Multimap<String, Foo> where we've grouped the Foo's by each tag of their Collection<String> getTags() function.

I am using java 8, so lambdas and method references are fine/encouraged.

For example if I have:

foo1, tags=a,b,c
foo2, tags=c,d
foo3, tags=a,c,e

I would get a Multimap<String, Foo> with:

a -> foo1, foo3
b -> foo1
c -> foo1, foo2, foo3
d -> foo2
e -> foo3

Answer: You can use custom collector for this:

Multimap<String, Foo> map = list.stream().collect(
    ImmutableMultimap::builder,
    (builder, value) -> value.getTags().forEach(tag -> builder.put(tag, value)),
    (builder1, builder2) -> builder1.putAll(builder2.build())
).build();

This does not cause extra side effects, is concurrent and more idiomatic.

You can also extract these ad-hoc lambdas into a full-fledged collector, something like this:

public static <T, K> Collector<T, ?, Multimap<K, T>> toMultimapByKey(Function<? super T, ? extends Iterable<? extends K>> keysMapper) {
    return new MultimapCollector<>(keysMapper);
}

private static class MultimapCollector<T, K> implements Collector<T, ImmutableMultimap.Builder<K, T>, Multimap<K, T>> {
    private final Function<? super T, ? extends Iterable<? extends K>> keysMapper;

    private MultimapCollector(Function<? super T, ? extends Iterable<? extends K>> keysMapper) {
        this.keysMapper = keysMapper;
    }

    @Override
    public Supplier<ImmutableMultimap.Builder<K, T>> supplier() {
        return ImmutableMultimap::builder;
    }

    @Override
    public BiConsumer<ImmutableMultimap.Builder<K, T>, T> accumulator() {
        return (builder, value) -> keysMapper.apply(value).forEach(k -> builder.put(k, value));
    }

    @Override
    public BinaryOperator<ImmutableMultimap.Builder<K, T>> combiner() {
        return (b1, b2) -> b1.putAll(b2.build());
    }

    @Override
    public Function<ImmutableMultimap.Builder<K, T>, Multimap<K, T>> finisher() {
        return ImmutableMultimap.Builder<K, T>::build;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }
}

Then the collection would look like this:

Multimap<String, Foo> map = list.stream().collect(toMultimapByKey(Foo::getTags));

You can also return EnumSet.of(Characteristics.UNORDERED) from characteristics() method if the order is not important for you. This can make internal collection machinery act more efficiently, especially in case of parallel reduction.


Library method to partition a collection by a predicate

Question: I have a collection of objects that I would like to partition into two collections, one of which passes a predicate and one of which fails a predicate. I was hoping there would be a Guava method to do this, but the closest they come is filter, which doesn't give me the other collection.

I would image the signature of the method would be something like this:

public static <E> Pair<Collection<E>, Collection<E>> partition(Collection<E> source, Predicate<? super E> predicate)

I realize this is super fast to code myself, but I'm looking for an existing library method that does what I want.

Answer: Use Guava's Multimaps.index.

Here is an example, which partitions a list of words into two parts: those which have length > 3 and those that don't.

List<String> words = Arrays.asList("foo", "bar", "hello", "world");

ImmutableListMultimap<Boolean, String> partitionedMap = Multimaps.index(words, new Function<String, Boolean>(){
    @Override
    public Boolean apply(String input) {
        return input.length() > 3;
    }
});
System.out.println(partitionedMap);

prints:

false=[foo, bar], true=[hello, world]

Clean Guava way to handle possibly-null collection

Question: I have a method which takes an argument Collection<Foo> foos, which could be NULL. I want to end up with a local copy of the input as an ImmutableSet. Right now my code looks like this:

if (foos == null)
{
  this.foos = ImmutableSet.of();
}
else
{
  this.foos = ImmutableSet.copyOf(foos);
}

Is there a cleaner way to do this? If foos was a simple parameter I could do something like Objects.firstNonNull(foos, Optional.of()) but I'm not sure if there is something similar to handle collections.

Answer: I don't see why you couldn't use Objects.firstNonNull:

this.foos = ImmutableSet.copyOf(Objects.firstNonNull(foos, ImmutableSet.of()));

You can save some typing with static imports, if that's your thing:

import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.ImmutableSet.of;
// snip...
this.foos = copyOf(Objects.firstNonNull(foos, of()));

Flattening an Iterable<Iterable<T>> in Guava

Question: Is there a flatten method in Guava - or an easy way to convert an Iterable<Iterable<T>> to an Iterable?

I have a Multimap<K, V> [sourceMultimap] and I want to return all values where the key matches some predicate [keyPredicate]. So at the moment I have:

Iterable<Collection<V>> vals = Maps.filterKeys(sourceMultimap.asMap(), keyPredicate).values();

Collection<V> retColl = ...;
for (Collection<V> vs : vals) retColl.addAll(vs);
return retColl;

I've looked through the Guava docs, but nothing jumped out. I am just checking I've not missed anything. Otherwise, I'll extract my three lines into a short flatten generic method and leave it as that.

Answer: The Iterables.concat method satisfies that requirement:

public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)

is there a Java equivalent to Javascript's "some" method?

Question: I have a collection and I would like to know if at least one element meets some condition. Essentially, what some does in JavaScript, I would like to do on a collection!

Answer: Check out Guava's Iterables class and its any() implementation.

More or less the same thing as the Commons Collections example in the other third part library, but genericized:

List<String> strings = Arrays.asList("ohai", "wat", "fuuuu", "kthxbai");
boolean well = Iterables.any(strings, new Predicate<String>() {
    @Override public boolean apply(@Nullable String s) {
        return s.equalsIgnoreCase("fuuuu");
    }
});
System.out.printf("Do any match? %s%n", well ? "Yep" : "Nope");

Is it possible to apply a function to a collection using Java Guava?

Question: I want to apply a function to a collection, map, etc, using Guava.

Basically, I need to resize the rows and columns of a Table separately so all rows and columns are of equal size, doing something like this:

Table<Integer, Integer, Cell> table = HashBasedTable.create(); Maps.transformValues(table.columnMap(), new ResizeFunction(BlockDimension.WIDTH)); Maps.transformValues(table.rowMap(), new ResizeFunction(BlockDimension.HEIGHT)); public interface Cell { int getSize(BlockDimension dimension); void setSize(BlockDimension dimension); }

I already have an idea of what the ResizeFunction should be. However, I need to apply it, not just return a Collection.

Answer: In Guava, you don't convert existing Lists, but instead create a new one using Iterables.transform:

final List<String> list = Arrays.asList("race", "box");
final List<String> transformed =
    Lists.newArrayList(Iterables.transform(list, new Function<String, String>() {

        @Override
        public String apply(final String input) {
            return new StringBuilder().append(input).append("car").toString();
        }
    }));
System.out.println(transformed);

Output:

[racecar, boxcar]

Or, if you don't need a List and a Collection will do, you can use a transformed live view:

final Collection<String> transformed =
    Collections2.transform(list, new Function<String, String>() {

        @Override
        public String apply(final String input) {
            return new StringBuilder().append(input).append("car").toString();
        }
    });

This Collection is a live view of the underlying one, so changes to list will be reflected in this Collection.