12. Collection (4)

Chapter Summary

  • SetSet
  • MapMap
  • QueueQueue
    • Priority QueuePriorityQueue
  • Collections and Iterators

SetSet

Set does not save duplicate elements. It prevents this duplication if you try to add multiple instances of the same object to the Set . The most common use of Sets is to test for belonging, making it easy to ask whether an object is in a Set . Because of this, lookup is usually the most important operation of a Set , so a HashSet implementation is usually chosen, which is optimized for fast lookups.

Set has the same interface as Collection , so it doesn't have any extra features, unlike the previous two different types of List . In fact, a Set is a Collection , it just behaves differently. (This is a typical application of inheritance and polymorphic ideas: showing different behaviors.) Set determines the attribution based on the "value" of the object. More complex content will be introduced in the Appendix: Collection Topics.

Here is an example using a HashSet that stores Integer objects :

import java.util.*;

public class SetOfInteger {
    
    
    public static void main(String[] args) {
    
    
        Random rand = new Random(47);
        Set<Integer> intset = new HashSet<>();
        for (int i = 0; i < 10000; i++) {
    
    
            intset.add(rand.nextInt(30));
        }
        System.out.println(intset);
    }
}

Insert image description here

10,000 random integers between 0 and 29 are added to the Set , so you can imagine each value being repeated many times. But as you can see from the results, only one instance of each number appears in the results.

HashSets in earlier versions of Java produced output with no apparent order. This is because HashSet uses hashing for the sake of speed , see Appendix: Chapter Set Topics. The order maintained by a HashSet is different from that of a TreeSet or LinkedHashSet because their implementations store elements differently. TreeSet stores elements in a red-black tree data structure, while HashSet uses hashing functions. LinkedHashSet also uses hashing to improve query speed, but seems to use a linked list to maintain the insertion order of elements. Apparently, the hashing algorithm has been changed so that now (the HashSet in the above example) the Integer is ordered. However, you should not rely on this behavior (the following example is not sorted):

import java.util.HashSet;
import java.util.Set;

public class SetOfString {
    
    
    public static void main(String[] args) {
    
    
        Set<String> colors = new HashSet<>();
        for (int i = 0; i < 100; i++) {
    
    
            colors.add("Yellow");
            colors.add("Blue");
            colors.add("Red");
            colors.add("Red");
            colors.add("Orange");
            colors.add("Yellow");
            colors.add("Blue");
            colors.add("Purple");
        }
        System.out.println(colors);
    }
}

Insert image description here

String objects don't seem to be sorted. To sort the results, one way is to use a TreeSet instead of a HashSet :

import java.util.*;

public class SortedSetOfString {
    
    
    public static void main(String[] args) {
    
    
        Set<String> colors = new TreeSet<>();
        for (int i = 0; i < 100; i++) {
    
    
            colors.add("Yellow");
            colors.add("Blue");
            colors.add("Red");
            colors.add("Red");
            colors.add("Orange");
            colors.add("Yellow");
            colors.add("Blue");
            colors.add("Purple");
        }
        System.out.println(colors);
    }
}

Insert image description here

One of the most common operations is to use contains()test membership, but there are also other operations that may remind you of the Venn diagrams you learned in grade school. relation):

import java.util.*;

public class SetOperations {
    
    
    public static void main(String[] args) {
    
    
        Set<String> set1 = new HashSet<>();
        Collections.addAll(set1,"A B C D E F G H I J K L".split(" "));
        set1.add("M");
        System.out.println("H: " + set1.contains("H"));
        System.out.println("N: " + set1.contains("N"));
        Set<String> set2 = new HashSet<>();
        Collections.addAll(set2, "H I J K L".split(" "));
        System.out.println("set2 in set1: " + set1.containsAll(set2));
        set1.remove("H");
        System.out.println("set1: " + set1);
        System.out.println("set2 in set1: " + set1.containsAll(set2));
        set1.removeAll(set2);
        System.out.println("set2 removed from set1: " + set1);
        Collections.addAll(set1, "X Y Z".split(" "));
        System.out.println("'X Y Z' added to set1: " + set1);
    }
}

Insert image description here

These method names are self-explanatory, and there are some other methods in the JDK documentation.

Being able to generate lists where each element is unique is a very useful feature. For example, suppose you want to list all the words in the SetOperations.java file above . By using the method described later in this book java.nio.file.Files.readAllLines(), you can open a file and read it as a List . Each String is in the input file. one line:

import java.util.*;
import java.nio.file.*;

public class UniqueWords {
    
    
    public static void
    main(String[] args) throws Exception {
    
    
        // 相对路径未获取到文件
        // List<String> lines = Files.readAllLines(Paths.get("SetOperations.java"));
        List<String> lines = Files.readAllLines(Paths.get("D:\\onJava\\myTest\\BASE0002\\SetOperations.java"));
        Set<String> words = new TreeSet<>();
        for (String line : lines) {
    
    
            for (String word : line.split("\\W+")) {
    
    
                if (word.trim().length() > 0) {
    
    
                    words.add(word);
                }
            }
        }
        System.out.println(words);
    }
}

Insert image description here

We step through each line in the file and String.split()split it into words using the regular expression \W + , which means it splits the string based on one or more (i.e. + ) non-word letters (regular Expressions will be introduced in the Strings chapter). Each resulting word is added to Set words . Because it is a TreeSet , the results are sorted. Here, sorting is done lexicographically, so uppercase and lowercase letters are separated. If you want to sort it alphabetically, you can pass the String.CASE_INSENSITIVE_ORDER comparator to the TreeSet constructor (a comparator is an object that establishes the sort order):

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class UniqueWordsAlphabetic {
    
    
    public static void
    main(String[] args) throws Exception {
    
    
        // 相对路径未获取到文件
        // List<String> lines = Files.readAllLines(Paths.get("SetOperations.java"));
        List<String> lines = Files.readAllLines(Paths.get("D:\\onJava\\myTest\\BASE0002\\SetOperations.java"));
        Set<String> words = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        for (String line : lines) {
    
    
            for (String word : line.split("\\W+")) {
    
    
                if (word.trim().length() > 0) {
    
    
                    words.add(word);
                }
            }
        }
        System.out.println(words);
    }
}

Insert image description here

The Comparator comparator will be introduced in detail in the array chapter.

map map

The ability to map objects to other objects is an efficient way to solve programming problems. For example, consider a program that is used to check the randomness of Java's Random class. Ideally, Random would produce a perfect distribution of numbers, but in order to test this, you need to generate a large number of random numbers and count the number of numbers that fall within various ranges. Map can easily solve this problem. In this case, the key is the number generated by Random , and the value is the number of times that number occurs:

import java.util.*;

public class Statistics {
    
    
    public static void main(String[] args) {
    
    
        Random rand = new Random(47);
        Map<Integer, Integer> m = new HashMap<>();
        for (int i = 0; i < 10000; i++) {
    
    
            // Produce a number between 0 and 20:
            int r = rand.nextInt(20);
            Integer freq = m.get(r); // [1]
            m.put(r, freq == null ? 1 : freq + 1);
        }
        System.out.println(m);
    }
}

Insert image description here

  • [1] The automatic wrapping mechanism converts a randomly generated int into an Integer reference that can be used with a HashMap (collections of primitive types cannot be used). If the key is not in the set, null is returned (meaning the first occurrence of the number). Otherwise, an Integer value associated with the key is generated , which is then incremented (again the auto-wrapping mechanism simplifies the expression, but the boxing and unboxing of the Integer does actually happen ).get()get()

The following example will use a String description to find Pet objects. It also shows using the containsKey()and containsValue()methods to test a Map to see if it contains a certain key or a certain value:

PetMap.java

public class PetMap {
    
    
    public static void main(String[] args) {
    
    
        Map<String, Pet> petMap = new HashMap<>();
        petMap.put("My Cat", new Cat("Molly"));
        petMap.put("My Dog", new Dog("Ginger"));
        petMap.put("My Hamster", new Hamster("Bosco"));
        System.out.println(petMap);
        Pet dog = petMap.get("My Dog");
        System.out.println(dog);
        System.out.println(petMap.containsKey("My Dog"));
        System.out.println(petMap.containsValue(dog));
    }
}

Pet.java

public class Pet extends Individual {
    
    
  public Pet(String name) {
    
     super(name); }
  public Pet() {
    
     super(); }
}

Cat.java

public class Cat extends Pet {
    
    
  public Cat(String name) {
    
     super(name); }
  public Cat() {
    
     super(); }
}

Dog.java

public class Dog extends Pet {
    
    
  public Dog(String name) {
    
     super(name); }
  public Dog() {
    
     super(); }
}

Insert image description here

Maps, like arrays and other Collections , can be easily extended to multiple dimensions: you only need to create a Map whose values ​​are also Maps (these Map values ​​can be other collections, or even other Maps ). As a result, collections can be easily combined to quickly produce powerful data structures. For example, assuming you're tracking people with multiple pets, all you need is a Map<Person, List> :

MapOfList.java

import java.util.*;

public class MapOfList {
    
    
    public static final Map<Person, List<? extends Pet>>
            petPeople = new HashMap<>();

    static {
    
    
        petPeople.put(new Person("Dawn"),
                Arrays.asList(
                        new Cymric("Molly"),
                        new Mutt("Spot")));
        petPeople.put(new Person("Kate"),
                Arrays.asList(new Cat("Shackleton"),
                        new Cat("Elsie May"), new Dog("Margrett")));
        petPeople.put(new Person("Marilyn"),
                Arrays.asList(
                        new Pug("Louie aka Louis Snorkelstein Dupree"),
                        new Cat("Stanford"),
                        new Cat("Pinkola")));
        petPeople.put(new Person("Luke"),
                Arrays.asList(
                        new Rat("Fuzzy"), new Rat("Fizzy")));
        petPeople.put(new Person("Isaac"),
                Arrays.asList(new Rat("Freckly")));
    }

    public static void main(String[] args) {
    
    
        System.out.println("People: " + petPeople.keySet());
        System.out.println("Pets: " + petPeople.values());
        for (Person person : petPeople.keySet()) {
    
    
            System.out.println(person + " has:");
            for (Pet pet : petPeople.get(person)) {
    
    
                System.out.println("    " + pet);
            }
        }
    }
}

Cat.java

public class Cat extends Pet {
    
    
  public Cat(String name) {
    
     super(name); }
  public Cat() {
    
     super(); }
}

Cymric.java

public class Cymric extends Manx {
    
    
  public Cymric(String name) {
    
     super(name); }
  public Cymric() {
    
     super(); }
}

Dog.java

public class Dog extends Pet {
    
    
  public Dog(String name) {
    
     super(name); }
  public Dog() {
    
     super(); }
}

Individual.java

import java.util.Objects;

public class
Individual implements Comparable<Individual> {
    
    
    private static long counter = 0;
    private final long id = counter++;
    private String name;

    public Individual(String name) {
    
    
        this.name = name;
    }

    // 'name' is optional:
    public Individual() {
    
    
    }

    @Override
    public String toString() {
    
    
        return getClass().getSimpleName() +
                (name == null ? "" : " " + name);
    }

    public long id() {
    
    
        return id;
    }

    @Override
    public boolean equals(Object o) {
    
    
        return o instanceof Individual &&
                Objects.equals(id, ((Individual) o).id);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(name, id);
    }

    @Override
    public int compareTo(Individual arg) {
    
    
        // Compare by class name first:
        String first = getClass().getSimpleName();
        String argFirst = arg.getClass().getSimpleName();
        int firstCompare = first.compareTo(argFirst);
        if (firstCompare != 0) {
    
    
            return firstCompare;
        }
        if (name != null && arg.name != null) {
    
    
            int secondCompare = name.compareTo(arg.name);
            if (secondCompare != 0) {
    
    
                return secondCompare;
            }
        }
        return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
    }
}

Manx.java

public class Manx extends Cat {
    
    
  public Manx(String name) {
    
     super(name); }
  public Manx() {
    
     super(); }
}

Mutt.java

public class Mutt extends Dog {
    
    
  public Mutt(String name) {
    
     super(name); }
  public Mutt() {
    
     super(); }
}

Person.java

public class Person extends Individual {
    
    
  public Person(String name) {
    
     super(name); }
}

Pet.java

public class Pet extends Individual {
    
    
  public Pet(String name) {
    
     super(name); }
  public Pet() {
    
     super(); }
}

Pug.java

public class Pug extends Dog {
    
    
  public Pug(String name) {
    
     super(name); }
  public Pug() {
    
     super(); }
}

Rat.java

public class Rat extends Rodent {
    
    
  public Rat(String name) {
    
     super(name); }
  public Rat() {
    
     super(); }
}

Rodent.java

public class Rodent extends Pet {
    
    
  public Rodent(String name) {
    
     super(name); }
  public Rodent() {
    
     super(); }
}

Insert image description here

A Map can return a Set of its keys , a Collection of its values , or a Set of its key-value pairs . keySet()method generates a Set consisting of all the keys in petPeople , which is used in the for-in statement to traverse the Map .

QueueQueue

A queue is a typical "first in, first out" (FIFO) collection. That is, you put things in from one end of the set and get them from the other end. The order in which things are put into the set is the same as the order in which they are taken out. Queues are often used as a reliable way to transfer objects from one area of ​​a program to another. Queues are particularly important in concurrent programming because they can safely transfer objects from one task to another.

LinkedList implements the Queue interface and provides some methods to support queue behavior, so LinkedList can be used as an implementation of Queue . By upcasting a LinkedList to a Queue , the following example uses the Queue -specific methods in the Queue interface :

import java.util.*;

public class QueueDemo {
    
    
    public static void printQ(Queue queue) {
    
    
        while (queue.peek() != null) {
    
    
            System.out.print(queue.remove() + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
    
    
        Queue<Integer> queue = new LinkedList<>();
        Random rand = new Random(47);
        for (int i = 0; i < 10; i++) {
    
    
            queue.offer(rand.nextInt(i + 10));
        }
        printQ(queue);
        Queue<Character> qc = new LinkedList<>();
        for (char c : "Brontosaurus".toCharArray()) {
    
    
            qc.offer(c);
        }
        printQ(qc);
    }
}

Insert image description here

offer()It is one of the unique methods of Queue . It inserts an element at the end of the queue if allowed, or returns false . peek()and element()both return the head element of the queue without deleting it, but if the queue is empty, nullpeek() is returned and NoSuchElementException is thrown . and both remove and return the head element of the queue, but if the queue is empty, null is returned and NoSuchElementException is thrown .element()poll()remove()poll()remove()

The automatic wrapping mechanism will automatically convert nextInt()the int result of into the Integer object required by queue , and convert the char c into the Character object required by qc . The Queue interface narrows access to LinkedList methods so that only the appropriate methods can be used, so fewer LinkedList methods will be accessible (it is actually possible to cast the Queue back to a LinkedList here , but at least we discourage this ).

Queue 's unique methods provide independent and complete functionality. In other words, Queue does not need to call methods inherited from Collection (only relies on Queue 's unique methods) to have the function of a queue.

Priority QueuePriorityQueue

First-in-first-out (FIFO) describes the most typical queuing discipline. A queue discipline is a rule that determines the next element to pop off the queue, given a set of elements in the queue. First in, first out: The next element to pop up should be the one with the longest waiting time.

Priority queue : The next element to pop is the most needed element (has the highest priority). For example, at an airport, passengers whose plane is about to take off but have not yet boarded may be pulled out of the queue (given top priority). If you build a messaging system, some messages are more important than others and should be processed as quickly as possible, regardless of the order in which they arrived. PriorityQueue was added in Java 5 to automate this behavior.

When calling method on PriorityQueueoffer() to insert an object, the object will be sorted in the queue. The default ordering uses the natural order of the objects in the queue, but this order can be modified by providing your own Comparator . PriorityQueue ensures that when calling peek()the poll()or remove()method, the element obtained will be the highest priority element in the queue.

Making PriorityQueue work with built-in types like Integer , String , and Character is a piece of cake. In the example below, the first set of values ​​are the same random values ​​as in the previous example, and you can see that they are popped out of the PriorityQueue in a different order than in the previous example:

import java.util.*;

public class PriorityQueueDemo {
    
    
    public static void main(String[] args) {
    
    
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        Random rand = new Random(47);
        for (int i = 0; i < 10; i++) {
    
    
            priorityQueue.offer(rand.nextInt(i + 10));
        }
        QueueDemo.printQ(priorityQueue);

        List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25);
        priorityQueue = new PriorityQueue<>(ints);
        QueueDemo.printQ(priorityQueue);
        priorityQueue = new PriorityQueue<>(ints.size(), Collections.reverseOrder());
        priorityQueue.addAll(ints);
        QueueDemo.printQ(priorityQueue);

        String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";
        List<String> strings = Arrays.asList(fact.split(""));
        PriorityQueue<String> stringPQ = new PriorityQueue<>(strings);
        QueueDemo.printQ(stringPQ);
        stringPQ = new PriorityQueue<>(strings.size(), Collections.reverseOrder());
        stringPQ.addAll(strings);
        QueueDemo.printQ(stringPQ);

        Set<Character> charSet = new HashSet<>();
        for (char c : fact.toCharArray()) {
    
    
            charSet.add(c); // Autoboxing
        }
        PriorityQueue<Character> characterPQ = new PriorityQueue<>(charSet);
        QueueDemo.printQ(characterPQ);
    }
}

Insert image description here

PriorityQueue allows duplication, and the smallest value has the highest priority (if it is a String , spaces can also be counted as values ​​and have a higher priority than letters). To show how to change the order by providing your own Comparator object, the third call to the PriorityQueue constructor, and the second call to the PriorityQueue use Collections.reverseOrder()the reverse-order Comparator generated by (newly added in Java 5) .

The last part adds a HashSet to eliminate duplicate Characters .

Integer , String and Character can be used with PriorityQueue because these classes already have natural ordering built-in. If you want to use your own class within a PriorityQueue , you must include additional functionality to produce a natural ordering, or you must provide your own Comparator . There is a more complex example demonstrating this situation in Appendix: Collection Topics.

Collections and Iterators

Collection is the root interface common to all sequence collections. It may be considered an "incidental interface", that is, an interface that appears because it expresses the commonality of several other interfaces. In addition, the java.util.AbstractCollection class provides a default implementation of Collection , and you can create subtypes of AbstractCollection to avoid unnecessary code duplication.

One reason to use interfaces is that they allow us to create more general code. By writing code against an interface rather than a concrete implementation, our code can be applied to a wider variety of objects. Therefore, if you write a method that accepts a Collection , the method can be applied to any class that implements Collection - this also allows a new class to choose to implement the Collection interface so that the method can use it. The collections in the standard C++ class library do not have a common base class - all commonality between collections is achieved through iterators. In Java, it seems sensible to follow the C++ approach, which is to use Iterators instead of Collections to represent commonalities between collections. However, these two methods are tied together, because implementing Collection means providing iterator()the method:

import pets.Pet;
import pets.PetCreator;

import java.util.*;

public class InterfaceVsIterator {
    
    
    public static void display(Iterator<Pet> it) {
    
    
        while (it.hasNext()) {
    
    
            Pet p = it.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void display(Collection<Pet> pets) {
    
    
        for (Pet p : pets) {
    
    
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
    
    
        List<Pet> petList = new PetCreator().list(8);
        Set<Pet> petSet = new HashSet<>(petList);
        Map<String, Pet> petMap = new LinkedHashMap<>();
        String[] names = ("Ralph, Eric, Robin, Lacey, Britney, Sam, Spot, Fluffy").split(", ");
        for (int i = 0; i < names.length; i++) {
    
    
            petMap.put(names[i], petList.get(i));
        }
        display(petList);
        display(petSet);
        display(petList.iterator());
        display(petSet.iterator());
        System.out.println(petMap);
        System.out.println(petMap.keySet());
        display(petMap.values());
        display(petMap.values().iterator());
    }
}

Insert image description here

Both versions of display()the method work with subtypes of Map or Collection . And both the Collection interface and Iteratordisplay() decouple methods from the specific implementation of the underlying collection.

In this case, either approach would work. In fact, Collection is a little more convenient because it is of type Iterable , so the for-indisplay(Collection) construct can be used in the implementation , which makes the code clearer.

When you need to implement an external class that is not a Collection , using an Iterator becomes very attractive because it may be difficult or cumbersome to have it implement the Collection interface. For example, if we create an implementation of Collection by inheriting a class that holds Pet objects , then we must implement all methods of Collection , even if we do not use them in methods. Although it would be easier by inheriting AbstractCollection , AbstractCollection also has and has not been implemented (abstract methods), and other methods in AbstractCollection will use them, so these two methods must be implemented in their own way:display()iterator()size()

CollectionSequence.java

import pets.Pet;
import pets.PetCreator;

import java.util.*;

public class CollectionSequence extends AbstractCollection<Pet> {
    
    
    private Pet[] pets = new PetCreator().array(8);

    @Override
    public int size() {
    
    
        return pets.length;
    }

    @Override
    public Iterator<Pet> iterator() {
    
    
        return new Iterator<Pet>() {
    
     // [1]
            private int index = 0;

            @Override
            public boolean hasNext() {
    
    
                return index < pets.length;
            }

            @Override
            public Pet next() {
    
    
                return pets[index++];
            }

            @Override
            public void remove() {
    
     // Not implemented
                throw new UnsupportedOperationException();
            }
        };
    }

    public static void main(String[] args) {
    
    
        CollectionSequence c = new CollectionSequence();
        InterfaceVsIterator.display(c);
        InterfaceVsIterator.display(c.iterator());
    }
}

InterfaceVsIterator.java

import pets.Pet;
import pets.PetCreator;

import java.util.*;

public class InterfaceVsIterator {
    
    
    public static void display(Iterator<Pet> it) {
    
    
        while (it.hasNext()) {
    
    
            Pet p = it.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void display(Collection<Pet> pets) {
    
    
        for (Pet p : pets) {
    
    
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
    
    
        List<Pet> petList = new PetCreator().list(8);
        Set<Pet> petSet = new HashSet<>(petList);
        Map<String, Pet> petMap = new LinkedHashMap<>();
        String[] names = ("Ralph, Eric, Robin, Lacey, " +
                "Britney, Sam, Spot, Fluffy").split(", ");
        for (int i = 0; i < names.length; i++) {
    
    
            petMap.put(names[i], petList.get(i));
        }
        display(petList);
        display(petSet);
        display(petList.iterator());
        display(petSet.iterator());
        System.out.println(petMap);
        System.out.println(petMap.keySet());
        display(petMap.values());
        display(petMap.values().iterator());
    }
}

Insert image description here

remove()The method is an "optional operation", you don't have to implement it here, if you call it, it will throw an exception.

  • [1] You might think that since an Iteratoriterator() is returned , the anonymous inner class definition can use diamond syntax and Java can infer the type. But this doesn't work, type inference is still very limited.

This example shows that if you implement Collection , you must also implement it iterator(), and implementing it alone is not much easier than iterator()inheriting from AbstractCollection . However, if the class has inherited other classes, then it cannot inherit AbstractCollection . In this case, to implement Collection , you must implement all methods in the interface. iterator()At this point, it's much easier to inherit and provide the ability to create iterators (implementing it separately ):

import pets.Pet;
import pets.PetCreator;

import java.util.*;

public class InterfaceVsIterator {
    
    
    public static void display(Iterator<Pet> it) {
    
    
        while (it.hasNext()) {
    
    
            Pet p = it.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void display(Collection<Pet> pets) {
    
    
        for (Pet p : pets) {
    
    
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
    
    
        List<Pet> petList = new PetCreator().list(8);
        Set<Pet> petSet = new HashSet<>(petList);
        Map<String, Pet> petMap = new LinkedHashMap<>();
        String[] names = ("Ralph, Eric, Robin, Lacey, " +
                "Britney, Sam, Spot, Fluffy").split(", ");
        for (int i = 0; i < names.length; i++) {
    
    
            petMap.put(names[i], petList.get(i));
        }
        display(petList);
        display(petSet);
        display(petList.iterator());
        display(petSet.iterator());
        System.out.println(petMap);
        System.out.println(petMap.keySet());
        display(petMap.values());
        display(petMap.values().iterator());
    }
}

Insert image description here

Generating an Iterator is the least coupled way to connect a sequence with a method that consumes that sequence, and it imposes far fewer constraints on the sequence class than implementing a Collection .

Guess you like

Origin blog.csdn.net/GXL_1012/article/details/132720570