betacode

Руководство Java Set

  1. Set
  2. Simple Examples
  3. stream()
  4. iterator()
  5. Как Set проверяет наличие дублирования?
  6. of(..)
  7. spliterator()
  8. toArray​(..)

1. Set

Set - это интерфейс в Java коллекции (Java Collection Framework) и является подинтерфейсом Collection, поэтому он обладает всеми функциями Collection.
Set- это неупорядоченная Collection(unordered Collection), не допускающая дублирования элементов и содержащая максимум 1 null-элемент. Если вы намеренно добавите дублированный элемент в Set, это действие будет проигнорировано и Set не изменится.
public interface Set<E> extends Collection<E>
SortedSet- это подинтерфейс Set. Он имеет возможность автоматически сортировать элементы по их естественному порядку или по предоставленному Comparator.
Иерархия классов реализует (implement) interface Set.
Методы interface Set:
Set interface
boolean add​(E e)  
boolean addAll​(Collection<? extends E> c)  

void clear()  

boolean contains​(Object o)  
boolean containsAll​(Collection<?> c)  

boolean equals​(Object o)  
int hashCode()  
boolean isEmpty()  
int size()  

boolean remove​(Object o)  
boolean removeAll​(Collection<?> c)  
boolean retainAll​(Collection<?> c)  

Object[] toArray()  
<T> T[] toArray​(T[] a)

Iterator<E> iterator()  
default Spliterator<E> spliterator()  

static <E> Set<E> copyOf​(Collection<? extends E> coll)  

static <E> Set<E> of()  
static <E> Set<E> of​(E e1)  
static <E> Set<E> of​(E... elements)  
static <E> Set<E> of​(E e1, E e2)  
static <E> Set<E> of​(E e1, E e2, E e3)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

2. Simple Examples

Set- это interface, поэтому для создания объекта Set необходимо создать класс, который его реализует, например HashSet, LinkedHashSet, TreeSet и т. д.
В следующем примере мы создаем объект HashSet с начальной емкостью (capacity) 10 элементов, и емкость увеличится на 80%, если его количество элементов превысит текущую емкость.
SetEx1.java
package org.o7planning.set.ex;

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

public class SetEx1 {

    public static void main(String[] args) {
        Set<String> set = new HashSet<String>(10, (float) 0.8);

        set.add("One");
        set.add("Two");
        set.add("Three");
        
        Iterator<String> it1 = set.iterator();
        while (it1.hasNext()) {
            System.out.println(it1.next());
        }
        
        System.out.println(" ----- ");
        
        // When duplication occurs.
        // It will add new element and remove old element.
        set.add("Two");
        set.add("Four");

        Iterator<String> it2 = set.iterator();
        while (it2.hasNext()) {
            System.out.println(it2.next());
        }
    }
}
Примечание:Set- это неупорядоченная Collection (unordered Collection), поэтому при печати элементов на Console вы можете получить немного другой результат.
Output:
One
Two
Three
 -----
One
Four
Two
Three
Array --> Set?
Пример преобразования массива в объект Set.
ArrayToSetEx.java
package org.o7planning.set.ex;

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

public class ArrayToSetEx {
    
    public static void main(String[] args) {
        Integer[] sourceArray = { 0, 3, 5, 3, 4, 5 };
        
        Set<Integer> targetSet = new HashSet<Integer>(Arrays.asList(sourceArray));
    
        for(Integer i : targetSet)  {
            System.out.println(i);
        }
    }  
}
Output:
0
3
4
5

3. stream()

Set - это подинтерфейс Collection, поэтому он наследует метод stream(). Доступ к элементам Collection через Stream делает ваш код кратким и легким для понимания:
Set_stream.java
package org.o7planning.set.ex;

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

public class Set_stream {

    public static void main(String[] args) {  
        Set<String> set = new HashSet<String>();
        
        set.add("a1");
        set.add("b1");
        set.add("a2");  
        set.add("c1");  
        set.add("d1");  
        set.add("e1");  
        
        set.stream() //
              .map(String::toUpperCase) // to upsercase
              .filter(s -> !s.startsWith("A")) // Not starts with "A".
              .forEach(System.out::println);  
    }  
}
Output:
E1
D1
C1
B1

4. iterator()

iterator() - это метод, наследующий от Collection, возвращающий объект Iterator для итерации (iterate) элементов Collection.
Iterator<E> iterator()
Set_iterator.java
package org.o7planning.set.ex;

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

public class Set_iterator {

    public static void main(String[] args) {  
        Set<String> set = new HashSet<String>();
        
        set.add("a1");
        set.add("b1");
        set.add("a2");  
        
        Iterator<String> ite = set.iterator();
        
        while(ite.hasNext()) {
            System.out.println(ite.next());
        }
    }  
}
Output:
a1
a2
b1

5. Как Set проверяет наличие дублирования?

Set- это Collection, которая не позволяет содержать дублированные элементы. Если вы намеренно добавите дублированный элемент в Set, это действие будет проигнорировано. Итак, вопрос в том, как "Set" проверяет дублирование?
SortedSet - это подинтерфейс Set. В этом разделе мы имеем дело только с чистыми типами Set (не SortedSet). Классы, представляющие чистый Set , - это HashSet, LinkedHashSet, CopyOnWriteArraySet и EnumSet.
Способ проверки SortedSet на дублирование полностью отличается от чистого Set и рассматривается в следующей статье:
HashSet / LinkedHashSet
HashSet LinkedHashSet) будут сравнивать hashcode(хэш-код) 2 элементов, а затем сравнивать 2 элемента напрямую с помощью их метода equals.
Взгляните на 2 примера HashSetDupTest1 и HashSetDupTest2 ниже, чтобы понять больше о приведенном выше описании.
HashSetDupTest1.java
package org.o7planning.set.test;

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

public class HashSetDupTest1 {

    public static class Student {
        private int studentId;
        private String studentName;
        
        public Student(int studentId, String studentName) {
            this.studentId = studentId;
            this.studentName = studentName;
        }
        public int getStudentId() {
            return studentId;
        }
        public String getStudentName() {
            return studentName;
        }
        @Override
        public boolean equals(Object other)  {
            if(other == null || !(other instanceof Student)) {
                return false;
            }
            Student o = (Student) other;
            return this.studentId == o.studentId;
        }
    }
    
    public static void main(String[] args) {
        Student s1 = new Student(1, "Tom");
        Student s2 = new Student(2, "Jerry");
        Student s3 = new Student(1, "Tom Cat"); // Same Id with s1.
        
        Set<Student> set = new HashSet<Student>();
        
        set.add(s1);
        set.add(s2);
        set.add(s3);

        for(Student s: set)  {
            System.out.printf("Student Id: %d / Name: %s (Hashcode: %s)\n", //
                    s.getStudentId(),s.getStudentName(),s.hashCode());
        }
    }
}
Output:
Student Id: 2 / Name: Jerry (Hashcode: 474675244)
Student Id: 1 / Name: Tom Cat (Hashcode: 932583850)
Student Id: 1 / Name: Tom (Hashcode: 1586600255)
Отредактируйте приведенный выше пример, переопределив (override) метод hashCode() в классе Student:
HashSetDupTest2.java
package org.o7planning.set.test;

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

public class HashSetDupTest2 {

    public static class Student {
        private int studentId;
        private String studentName;
        
        public Student(int studentId, String studentName) {
            this.studentId = studentId;
            this.studentName = studentName;
        }
        public int getStudentId() {
            return studentId;
        }
        public String getStudentName() {
            return studentName;
        }
        @Override
        public boolean equals(Object other)  {
            if(other == null || !(other instanceof Student)) {
                return false;
            }
            Student o = (Student) other;
            return this.studentId == o.studentId;
        }
        @Override
        public int hashCode() { // -----> Override hashCode() method.
            return this.studentName.charAt(0);
        }
    }
    
    public static void main(String[] args) {
        Student s1 = new Student(1, "Tom");   // Hashcode: 84 ('T')
        Student s2 = new Student(1, "Tom Cat"); // Hashcode: 84 ('T')
        
        Student s3 = new Student(2, "Jerry"); // Hashcode: 74 ('J')
        
        Student s4 = new Student(4, "Daffy"); // Hashcode: 68 ('D')
        Student s5 = new Student(5, "Donald"); // Hashcode: 68 ('D')
        
        
        Set<Student> set = new HashSet<Student>();
        
        set.add(s1);
        set.add(s2); // a Duplication (Ignored!)
        set.add(s3);
        set.add(s4);  
        set.add(s5);  

        for(Student s: set)  {
            System.out.printf("Student Id: %d / Name: %s (Hashcode: %s)\n", //
                    s.getStudentId(),s.getStudentName(),s.hashCode());
        }
    }
}
Output:
Student Id: 1 / Name: Tom (Hashcode: 84)
Student Id: 4 / Name: Daffy (Hashcode: 68)
Student Id: 5 / Name: Donald (Hashcode: 68)
Student Id: 2 / Name: Jerry (Hashcode: 74)
CopyOnWriteArraySet
CopyOnWriteArraySet напрямую сравнивает 2 элемента с помощью их метода equals.
Взгляните на 2 примера CopyOnWriteArraySetDupTest1 и CopyOnWriteArraySetDupTest2 ниже, чтобы понять больше о приведенном выше описании.
CopyOnWriteArraySetDupTest1.java
package org.o7planning.set.test;

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetDupTest1 {

    public static class Employee {
        private int empId;
        private String empName;
        
        public Employee(int empId, String empName) {
            this.empId = empId;
            this.empName = empName;
        }
        public int getEmpId() {
            return empId;
        }
        public String getEmpName() {
            return empName;
        }
        // Employee class uses equals(Object) method inherited from Object class.
    }
    
    public static void main(String[] args) {
        Employee s1 = new Employee(1, "Tom");    
        Employee s2 = new Employee(2, "Jerry");  
        Employee s3 = new Employee(1, "Tom Cat");  
        
        Set<Employee> set = new CopyOnWriteArraySet<Employee>();
        
        set.add(s1);
        set.add(s2);
        set.add(s3);  

        for(Employee s: set)  {
            System.out.printf("Emp Id: %d / Name: %s\n", //
                    s.getEmpId(),s.getEmpName());
        }
    }
}
Output:
Emp Id: 1 / Name: Tom
Emp Id: 2 / Name: Jerry
Emp Id: 1 / Name: Tom Cat
Отредактируйте приведенный выше пример, переопределив (override) метод equals(Object) в классе Employee:
CopyOnWriteArraySetDupTest2.java
package org.o7planning.set.test;

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetDupTest2 {

    public static class Employee {
        private int empId;
        private String empName;
        
        public Employee(int studentId, String studentName) {
            this.empId = studentId;
            this.empName = studentName;
        }
        public int getEmpId() {
            return empId;
        }
        public String getEmpName() {
            return empName;
        }
        @Override
        public boolean equals(Object other)  { // -----> Override equals() method.
            if(other == null || !(other instanceof Employee)) {
                return false;
            }
            Employee o = (Employee) other;
            return this.empId == o.empId;
        }
    }
    
    public static void main(String[] args) {
        Employee s1 = new Employee(1, "Tom");   
        Employee s2 = new Employee(2, "Jerry");  
        Employee s3 = new Employee(1, "Tom Cat");
        
        Set<Employee> set = new CopyOnWriteArraySet<Employee>();
        
        set.add(s1);
        set.add(s2);
        set.add(s3); // a Duplication.

        for(Employee s: set)  {
            System.out.printf("Emp Id: %d / Name: %s\n", //
                    s.getEmpId(),s.getEmpName());
        }
    }
}
Output:
Emp Id: 1 / Name: Tom
Emp Id: 2 / Name: Jerry

6. of(..)

Статический метод Set.of(..) возвращает объект Set фиксированного размера, исключение создается, если входные параметры дублируются. Этот объект Setне поддерживает дополнительные методы: add, remove, set и clear.
static <E> Set<E> of()  
static <E> Set<E> of​(E e1)  
static <E> Set<E> of​(E... elements)  
static <E> Set<E> of​(E e1, E e2)  
static <E> Set<E> of​(E e1, E e2, E e3)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)  
static <E> Set<E> of​(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
Set_of.java
package org.o7planning.set.ex;

import java.util.Iterator;
import java.util.Set;

public class Set_of {

    public static void main(String[] args) {
        Set<Integer> set = Set.of(1, 2, 5, 3, 7, 9, 0);

        Iterator<Integer> it2 = set.iterator();
        while (it2.hasNext()) {
            System.out.println(it2.next());
        }
    }
}
Примечание: Set- это неупорядоченная Collection (unordered Collection), поэтому при печати элементов на Console вы можете получить немного другой результат.
Output:
2
3
5
7
9
0
1

7. spliterator()

Создайте объект Spliterator для обхода и разбиения (traversing and partitioning) элементов Set.
default Spliterator<E> spliterator()
Spliteratorшироко используется для обхода и разбиения (traversing and partitioning) различных источников данных, таких как Collection (List, Set, Queue), BaseStream, array.
  • Руководство Java Spliterator

8. toArray​(..)

Метод toArray(..) возвращает массив, содержащий все элементы Set.
Object[] toArray()  

<T> T[] toArray​(T[] a)

// Java 11, The default method, inherited from Collection.
default <T> T[] toArray​(IntFunction<T[]> generator)
Set_toArray.java
package org.o7planning.set.ex;

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

public class Set_toArray {

    public static void main(String[] args) {  
        Set<String> set = new HashSet<String>();
        
        set.add("a1");
        set.add("b1");
        set.add("a2");  
        
        String[] array = new String[set.size()];
        
        set.toArray(array);
        
        for(String s: array) {
            System.out.println(s);
        }
    }  
}
Output:
a1
a2
b1