Monday, 20 February 2017

Java 8 Collection improvements

Background

With introduction of functional interfaces and Lambda expressions there are some new APIs introduced in collection class. In this post we will look at those.


Conditional removal [Collection.removeIf]

There is a new method added in Collection interface as -

  • boolean removeIf(Predicate<? super E> filter)

This basically removes elements from the list that match the predicate. No magic here if you see the default implementation it is as follows -

    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }

So you basically iterate on your collection using a iterator and remove all elements that match your predicate condition. 

Let's see an example now -

        List<String> countriesList = new ArrayList<>();
        countriesList.add("India");
        countriesList.add("Srilanka");
        countriesList.add("Nepal");
        countriesList.add("Italy");
        countriesList.add("Bhutan");
        countriesList.add("Ireland");
        System.out.println("Before : " + countriesList);
        countriesList.removeIf(s -> s.startsWith("I"));
        System.out.println("After : " + countriesList);

Output is :
Before : [India, Srilanka, Nepal, Italy, Bhutan, Ireland]
After : [Srilanka, Nepal, Bhutan]

As you can see all Strings in the list starting with 'I' are removed as defined by the predicate.


Updating all elements(List.replaceAll)

Another method that is introduced is - 

  • void replaceAll(UnaryOperator<E> o)
It replaces all the elements in the current List to new values based on the UnaryOperator.  Let's revisit above example with minor modification -

        List<String> countriesList = new ArrayList<>();
        countriesList.add("India");
        countriesList.add("Srilanka");
        countriesList.add("Nepal");
        countriesList.add("Italy");
        countriesList.add("Bhutan");
        countriesList.add("Ireland");
        System.out.println("Before : " + countriesList);
        countriesList.replaceAll(s -> "Miss " + s);
        System.out.println("After : " + countriesList);


and the output is :
Before : [India, Srilanka, Nepal, Italy, Bhutan, Ireland]
After : [Miss India, Miss Srilanka, Miss Nepal, Miss Italy, Miss Bhutan, Miss Ireland]

NOTE : Recollect UnaryOperator takes a single argument of type t and returns a value of same type t. If you wish to recollect common functional interfaces check out the links in the Related links section below.

Iterating over a List (List.forEach)

Another useful method that is added in List is -
  • public void forEach(Consumer<? super E> action)
It lets you take an action for  all the elements in the List. Lets see this now.

        List<String> countriesList = new ArrayList<>();
        countriesList.add("India");
        countriesList.add("Srilanka");
        countriesList.add("Nepal");
        countriesList.add("Italy");
        countriesList.add("Bhutan");
        countriesList.add("Ireland");
        System.out.println("Before : " + countriesList);
        countriesList.forEach(System.out::println);
        System.out.println("After : " + countriesList);


and the output is -
Before : [India, Srilanka, Nepal, Italy, Bhutan, Ireland]
India
Srilanka
Nepal
Italy
Bhutan
Ireland
After : [India, Srilanka, Nepal, Italy, Bhutan, Ireland]


NOTE : Careful. Do not alter the List with the action or you will get - java.util.ConcurrentModificationException

NOTE : Above method reference System.out::println is same as saying s -> System.out.println(s)

New APIs added in Map

New APIs added -
  1. merge()
  2. putIfAbsent() : puts in map is key is not present or the value is null
  3. computeIfPresent() : calls the BiFunction when the requested key is found
  4. computeIfAbsent() : calls the BiFunction when the key isn’t present or
    is null
 Let's see merge first -

It's method is as follows -

    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if(newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }
Above is the default implementation in Map method.  Quick observation :
  1. If old value is null, bifunction is never called. 
  2. If mapping function returns null key is removed from the Map.
 computeIfAbsent and computeIfPresent are again similar. They also take bifunction. computeIfAbsent executes the mapping function if key is not present or value is null and computeIfPresent executes the mapping function if key is present and the value is not null. Following are it's signatures -

  •     default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
  •     default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)


Related Links


t> UA-39527780-1 back to top