Collection and Iterator interface -- Java Collection Series

The Collection interface is the parent interface of the List, Set and Queue interfaces. The methods defined in the interface can be used to operate both the Set Collection and the List and Queue Collection.

1. Collection interface method

1.1 method API

  • boolean add(Object o)
    Add an element to the collection and return true when the collection object is changed by the add operation.
  • boolean addAll(Collection c)
    Returns true when the added operation changes.
  • void clear()
    Clear all elements in the collection, and change the collection length to 0.
  • boolean contains(Object o)
    Returns whether the collection contains the specified element.
  • boolean containsAll(Collection c)
    Returns whether the collection contains all the elements in collection c.
  • boolean isEmpty()
    Returns whether the collection is empty. Returns true when the collection length is 0, otherwise false.
  • Iterator iterator()
    Returns an Iterator object that traverses the elements in the collection.
  • boolean remove(Object o)
    Delete the specified element o in the collection. When the collection contains one or more elements o, the method only deletes the first qualified element, and the method will return true.
  • boolean removeAll(Collection c)
    Remove the elements contained in set c from the set (equivalent to subtracting set c from the set calling the method). If one or more elements are deleted, the method returns true.
  • boolean retainAll(Collection c)
    Remove the elements not contained in collection c from the collection (equivalent to turning the collection that calls the method into the intersection of the collection and collection c). If the operation changes the collection that calls the method, the method returns true.
  • int size()
    Returns the number of elements in the collection.
  • Object[] toArray()
    Convert the set into an array, and all the set elements become the corresponding array elements.

1.2 procedure cases

package com.yuxx.javase.collection;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest {
    public static void main(String[] args) {
        Collection bookC = new ArrayList();

        bookC.add("Journey to the West");
        bookC.add("The Dream of Red Mansion");
        bookC.add("Romance of the Three Kingdoms");
        System.out.println("bookC Number of elements in the collection:" + bookC.size());//Number of elements in the bookC collection: 3

        boolean rFlag1 = bookC.remove("Water Margin");
        boolean rFlag2 = bookC.remove("Romance of the Three Kingdoms");

        System.out.println("Delete Water Margin return:"+ rFlag1);//Delete Water Margin return: false
        System.out.println("Delete the romance of Three Kingdoms and return:"+ rFlag2);//Delete three kingdoms return: true

        System.out.println("bookC Number of elements in the collection:" + bookC.size());//Number of elements in the bookC collection: 2

        System.out.println("bookC Whether the collection contains\"Journey to the West\"Character string:" + bookC.contains("Journey to the West"));//Whether the bookC collection contains the "journey to the west" string: true

        bookC.add("Water Margin");

        Collection bookA = new ArrayList();
        bookA.add("Romance of the Three Kingdoms");
        bookA.add("Water Margin");
        System.out.println("bookC Whether the collection contains all bookA Collection:" + bookC.containsAll(bookA));//Whether the bookC collection completely contains the bookA collection: false

        bookC.removeAll(bookA);
        System.out.println("bookC Elements in collection:" + bookC);//Elements in the bookC collection: [journey to the west, dream of Red Mansions]

        bookA.retainAll(bookC);
        System.out.println("bookA Elements in collection:" + bookA);//Elements in the bookA collection: []

        bookC.clear();
        System.out.println("bookC Elements in collection:" + bookC);//Elements in the bookC collection: []
    }
}

When the println() method of System.out is used to output Collection objects, the form of [ele1,ele2,...] will be output, because all Collection implementation classes override the toString() method, which can output all elements in the Collection at one time.

2. Operation set element

2.1 traversing a collection using Lambda expressions

Java 8 adds a forEach(Consumer action) default method for the iterator interface. The parameter type is a functional interface. The Iterator interface is the parent interface of the Collection interface, so the Collection can also call this method directly.

When the program calls Iterator's forEach(Consumer action) to traverse the collection elements, the program will pass the collection elements to the Consumer's accept (t t t) method in turn (the only abstract method in the interface). Because Consumer is a functional interface, you can use Lambda expressions to traverse collection elements.

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;

public class CollectionForEach {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");
        books.forEach( obj -> System.out.println(obj));
        /*
        Water Margin
        Romance of the Three Kingdoms
        The Dream of Red Mansion
        Journey to the West
         */
    }
}

2.2 using Java 8 enhanced Iterator to traverse collection elements

The Iterator interface is also a member of the Java collection framework, but it is different from collection series and Map series: Collection Series and Map series are mainly used to hold other objects, while Iterator is mainly used to traverse (i.e. iterate access) the elements in collection collection, and Iterator objects are also called iterators.

Methods defined in Iterator interface:

  • boolean hashNext()
    Returns true if the iterated collection element has not been traversed.
  • Object next()
    Returns the next element in the collection.
  • void remove()
    Delete the element returned by the next method last time in the collection.
  • void forEachRemaining(Comsumer action)
    This is a new default method for Iterator in Java 8, which uses Lambda expressions to traverse collection elements.
package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class IteratorTest {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        Iterator iterator = books.iterator();
        while (iterator.hasNext()){
            String book = (String) iterator.next();
            System.out.println(book);
            if("The Dream of Red Mansion".equals(book)){
                iterator.remove();//Delete the element returned by the last next() method
            }
            //Assigning a value to the book variable does not change the set element itself
            book = "Strange Tales from a strange studio";
        }
        System.out.println(books);
        /*
        Water Margin
        Romance of the Three Kingdoms
        The Dream of Red Mansion
        Journey to the West
        [Outlaws of the marsh, romance of the Three Kingdoms, journey to the West]
         */
    }
}

 

As you can see from the above code, Iterator is only used to traverse the collection, and Iterator itself does not provide the ability to hold objects. If you need to create an Iterator object, you must have an iterated collection.

In line 23 above, after assigning a value to the book variable, print the books collection again. The elements in the collection have not changed. That is, when Iterator is used to iterate over a set, Iterator does not pass the set element itself to the iteration variable, but the value of the set element to the iteration variable.

When using Iterator to access Collection collection elements iteratively, the elements in the Collection cannot be changed. Only the Collection elements returned by the next() method last time can be deleted through Iterator's remove() method. If the Collection's remove method is used, a java.util.ConcurrentModificationException exception will be thrown. Code case:

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class IteratorErrorTest {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        Iterator iterator = books.iterator();
        while (iterator.hasNext()){
            String book = (String) iterator.next();
            System.out.println(book);
            if("The Dream of Red Mansion".equals(book)){
                books.remove(book);
            }
        }
        System.out.println(books);
    }
}

Console print results:

The Iterator iterator adopts the fast failure mechanism. Once the collection has been modified (usually by other threads in the program) during the iteration, the program immediately raises the ConcurrentModificationException exception instead of displaying the modified result, which can avoid potential problems caused by sharing resources.

2.3 traversing Iterator with Lambda expression

Java 8 adds a foreachmaintaining (Consumer action) method for Iterator, and the Consumer parameter required for this method is also a functional interface. When the program calls Iterator's forEachRemaining(Consumer action) to traverse the set parameter, the program will pass the set element to Consumer's accept (t t t) method (the only abstract method in the interface) in turn.

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class IteratorEach {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        Iterator iterator = books.iterator();
        iterator.forEachRemaining(obj -> System.out.println(obj));
    }
}

2.4 traversing set elements with foreach loop

Java 5 provides a foreach loop to iterate through collection elements.

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class ForeachTest {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        for (Object obj : books) {
            String book = (String) obj;
            System.out.println(book);
            if ("Romance of the Three Kingdoms".equals(book)) {
                //The following code will throw a ConcurrentModificationException
                books.remove(book);
            }
        }
        System.out.println(books);
    }
}

Similar to using Iterator interface to access set elements iteratively, the iterative variables in foreach loop are not set elements themselves. The system just assigns the values of set elements to iterative variables in turn, so there is no meaning to modify the values of iterative variables in foreach loop.

Similarly, when a foreach loop is used to access a collection element, the collection cannot be modified, otherwise a ConcurrentModificationException exception will be thrown.

2.5 using Java 8's new predict operation set

Java 8 adds a removeif (predict filter) method to the Collection, which will batch delete all elements that meet the filter conditions. This method requires a Predicate object as a parameter, and Predicate is also a functional interface, so Lambda expressions can be used as parameters.

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;

public class PredicateTest {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        books.removeIf(book -> ((String)book).length() <=3);
        System.out.println(books);
    }
}

The above program deleted elements with length less than or equal to 3. In fact, there may be more statistical requirements. If you use traditional programming methods to complete these requirements, you need to perform three cycles, but only one method is needed to use Predicate.

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.function.Predicate;

public class PredicateTest2 {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        System.out.println(callAll(books,book -> ((String)book).length() > 3));
        System.out.println(callAll(books,book -> ((String)book).contains("Westward Journey")));
    }

    public static int callAll(Collection books, Predicate predicate){
        int total = 0;
        for (Object obj : books) {
            if(predicate.test(obj)){
                total ++;
            }
        }
        return total;
    }
}

2.6 using the new Stream operation set of Java 8

Java 8 also adds popular API s such as Stream, IntStream, LongStream and doublestrream, which represent multiple elements supporting serial and parallel aggregation operations. Among the above four interfaces, Stream is a general Stream interface, while IntStream, LongStream and DoubleStream represent streams with element types of int, long and double.

Java 8 also provides a corresponding Builder for each of the above stream API s, such as Stream.Builder, IntStream.Builder, LongStream.Builder, DoubleStream.Builder, through which developers can create corresponding streams.

The steps to use Stream independently are as follows:

  • Use the builder() class method of Stream or XxxStream to create the Builder corresponding to the Stream.
  • Repeatedly call Builder's add() method to add multiple elements to the flow.
  • Call Builder's build() method to get the corresponding Stream.
  • Call the Stream's aggregate method.

The fourth step can call different methods according to specific needs. Stream provides a large number of aggregation methods for users to call. For most aggregation methods, each stream can only be executed once. Code case:

package com.yuxx.javase.collection;

import java.util.stream.IntStream;

public class IntStreamTest {
    public static void main(String[] args) {
        IntStream intStream = IntStream.builder().add(1).add(28).add(15).add(89).build();
        //The following code that calls the aggregate method can only execute one line at a time
        System.out.println("Maximum:" + intStream.max().getAsInt());
        System.out.println("Minimum:" + intStream.min().getAsInt());
        System.out.println("And:" + intStream.sum());
        System.out.println("Total:" + intStream.count());
        System.out.println("Average:" + intStream.average().getAsDouble());
        System.out.println("Whether all elements are less than 100:" + intStream.allMatch( intNum -> intNum < 100));
        System.out.println("Contains any element greater than 50:" + intStream.anyMatch( intNum -> intNum > 50));
        //Map intStream to a new Stream. Each element of the new Stream is twice the original Stream
        IntStream insStream2 = intStream.map(intNum -> intNum * 2);
        insStream2.forEach(System.out::println);
    }
}

3. A brief introduction to stream

Stream provides a large number of methods for aggregation, which can be either "intermediate" or "terminal".

  • Intermediate method
    Intermediate operations allow the flow to remain open and allow direct calls to subsequent methods. The return value of the intermediate method is another stream.
  • Terminal method
    The end method is the final operation of convection. When an end method is executed on a Stream, the Stream is "consumed" and is no longer available.

In addition, flow has the following two characteristics:

  • Stateful approach
    This method will add some new attributes to the flow, such as the uniqueness of the elements, the maximum number of elements, ensuring that the elements are processed in a sort way, etc. Stateful methods often require more performance overhead.
  • Short circuit method
    The short circuit method can end the convection operation as early as possible without checking all elements.

3.1 common intermediate methods of stream

  • filter(Predicate predicate)
    Filter all elements in the Stream that do not conform to the predicate.
  • maxToXxx(ToXxxFunction mapper)
    Use the elements in the toxxfunction stream to perform a one-to-one transformation. The new stream returned by this method contains all the elements generated by the toxxfunction transformation.
  • peek(Consumer action)
    Perform some operations on each element in turn, and the flow returned by this method contains the same elements as the original flow. This method is mainly used for debugging.
  • distinct()
    This method is used to sort all the duplicate elements in the flow (the criterion for judging the repetition is to use equals() comparison to return true). This is a stateful approach.
  • sorted()
    This method is used to ensure that the elements in the flow are in an orderly state in the subsequent access, which is a stateful method.
  • limit(long maxSize)
    This method is used to ensure the maximum number of elements allowed to access in the subsequent access to the stream. This is a stateful, short-circuit method.

3.2 common end methods of stream

  • forEach(Consumer action)
    Traverse all elements in the flow, and perform action on each element.
  • toArray()
    Converts all elements of the stream to an array.
  • reduce()
    There are three overloaded versions of this method, all of which are used to merge elements in a stream by some operation.
  • min()
    Returns the minimum value of all elements in the stream.
  • max()
    Returns the maximum value of all elements in the stream.
  • count()
    Returns the number of all elements in the stream.
  • anyMatch(Predicate predicate)
    Determines whether the stream contains an element that meets the Predicate condition.
  • allMatch(Predicate predicate)
    Determine whether each element in the flow meets the Predicate condition.
  • noneMatch(Predicate predicate)
    Determines whether all elements in the stream do not meet the Predicate condition.
  • findFirst()
    Returns the first element in the stream.
  • findAny()
    Returns any element in the stream.

Java 8 allows the use of streaming API to operate collections. The Collection interface provides a stream() default method that returns the corresponding streams of the Collection. Next, the Collection elements can be operated through the streaming API. Stream can aggregate Collection elements as a whole, so stream greatly enriches the function of Collection.

Procedure case:

package com.yuxx.javase.collection;

import java.util.Collection;
import java.util.HashSet;

public class CollectionStream {
    public static void main(String[] args) {
        Collection books = new HashSet();
        books.add("Journey to the West");
        books.add("Water Margin");
        books.add("Romance of the Three Kingdoms");
        books.add("The Dream of Red Mansion");

        System.out.println( books.stream().filter( book -> ((String)book).contains("Westward Journey")).count());
        System.out.println( books.stream().filter( book -> ((String)book).length() > 3).count());
        books.stream().mapToInt( book -> ((String)book).length()).forEach(System.out::println);

    }
}

Keywords: Programming Java Lambda less

Added by teamshultz on Tue, 31 Dec 2019 07:03:59 +0200