Wykład 13
Programowanie generyczne to koncepcja w programowaniu, która pozwala na pisanie kodu, który może być używany z różnymi typami danych, bez konieczności powtarzania tego samego kodu dla każdego typu danych. Jest to szczególnie przydatne w językach programowania silnie typowanych, takich jak Java, C# czy C++, gdzie typy danych muszą być określone podczas kompilacji. Oto kluczowe aspekty programowania generycznego:
Typy Parametryzowane: Programowanie generyczne umożliwia tworzenie klas, interfejsów i metod, które działają na “typach generycznych”. Te typy generyczne są określone jako parametry, zazwyczaj reprezentowane przez litery, takie jak T, E, K, V itp.
Zwiększona Znacząco Bezpieczeństwo Typów: Dzięki temu, że typy są określone podczas kompilacji, programowanie generyczne pomaga uniknąć błędów związanych z nieprawidłowym rzutowaniem typów, które mogą wystąpić w trakcie działania programu.
Ograniczenia Typów: Możliwe jest narzucenie ograniczeń na typy generyczne, tak aby akceptowały tylko klasy, które spełniają określone wymagania (np. dziedziczenie po konkretnej klasie bazowej lub implementowanie określonego interfejsu).
Kod Współużytkowany: Kod napisany w sposób generyczny może być używany z różnymi typami danych, co zmniejsza redundancję i ułatwia utrzymanie kodu.
Kompilacja Typu Bezpiecznego: Podczas kompilacji, kompilator sprawdza, czy kod generyczny jest używany poprawnie zgodnie z określonymi typami, co zapewnia wyższe bezpieczeństwo typów i pomaga w wykrywaniu błędów na wcześniejszym etapie rozwoju oprogramowania.
Przykładowe Zastosowania:
List<T>
, Map<K,V>
), co pozwala na tworzenie kolekcji, które mogą przechowywać elementy dowolnego typu, jednocześnie zapewniając bezpieczeństwo typów.Przykład w Javie:
Box<T>
, możesz utworzyć jej instancję jako Box<Integer>
lub Box<String>
. Tutaj Box<Integer>
i Box<String>
są typami parametryzowanymi.Typ Generyczny (Generic Type) Typ generyczny to termin ogólnie odnoszący się do klas, interfejsów i metod, które używają typów parametryzowanych. Obejmuje on zarówno definicję klasy generycznej (jak Box<T>
), jak i konkretne typy parametryzowane (jak Box<Integer>
).
Szablon Klas (Class Template) Szablon klas jest pojęciem bardziej związanym z językami programowania takimi jak C++, które stosują “templates” do osiągnięcia podobnych celów, co generyki w Javie. Szablon klasy w C++ jest schematem dla tworzenia klas lub funkcji, które mogą działać z dowolnym typem.
Przykład w C++:
Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
Projekt W11, pakiet: example17
package example17;
// Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
package example17;
//Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class ArrayAlg {
public static Pair<String> minmax(String[] a) {
if (a == null || a.length == 0) {
return null;
}
String min = a[0];
String max = a[0];
for (int i = 1; i < a.length; i++) {
if (min.compareTo(a[i]) > 0) {
min = a[i];
}
if (max.compareTo(a[i]) < 0) {
max = a[i];
}
}
return new Pair<>(min, max);
}
}
package example17;
public class TestPair {
public static void main(String[] args) {
Pair<String> p = new Pair<>("Jan", "Kowalski");
System.out.println(p.getFirst() + " " + p.getSecond());
p.setFirst("Adam");
p.setSecond("Nowak");
System.out.println(p.getFirst() + " " + p.getSecond());
String[] words = {"Ala", "ma", "kota", "i", "psa"};
Pair<String> mm = ArrayAlg.minmax(words);
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
}
}
W programowaniu generycznym w Javie stosuje się pewne konwencje dotyczące oznaczeń typów generycznych, aby ułatwić zrozumienie kodu. Oto najczęściej używane oznaczenia:
E - Element: Jest używany głównie w kolekcjach, jak java.util.List<E>
, java.util.Set<E>
, gdzie E oznacza typ elementów w kolekcji.
K - Key: Używany w kontekście map i wpisów mapy, gdzie K reprezentuje typ klucza. Na przykład w java.util.Map<K, V>
.
V - Value: Również używany w mapach, gdzie V oznacza typ wartości. W java.util.Map<K, V>
, K to klucz, a V to wartość.
T - Type: Jest to ogólny typ, który może być używany w dowolnym kontekście. Na przykład, w klasach generycznych jak java.util.ArrayList<T>
, gdzie T oznacza typ przechowywanych elementów.
N - Number: Czasami używany do oznaczania liczbowych typów danych, szczególnie w klasach rozszerzających java.lang.Number
.
S, U, V itd.: Te litery są używane, gdy są potrzebne dodatkowe typy generyczne, i zwykle są stosowane w kolejności alfabetycznej.
https://docs.oracle.com/javase/tutorial/java/generics/types.html
Tworzenie metod generycznych umożliwia pisaniu metod, które mogą operować na różnych typach danych, jednocześnie zapewniając bezpieczeństwo typów w czasie kompilacji. Oto jak możesz tworzyć metody generyczne:
Deklaracja Typu Generycznego: Typ generyczny jest deklarowany przed typem zwracanym metody. Używa się do tego liter jak T, E, K, V, itd., które działają jako zmienne reprezentujące typy.
Przykład:
W tym przykładzie <T>
przed void
oznacza, że metoda printArray
jest generyczna i operuje na typie T
.
Używanie Typów Generycznych w Ciele Metody: Możesz używać tych typów generycznych jako typów zmiennych, parametrów i typów zwracanych w metodzie.
Ograniczenia Typów (Type Bounds): Możesz ograniczyć rodzaje typów, które mogą być używane z danym typem generycznym, używając słowa kluczowego extends
(dla klas i interfejsów) lub super
(dla ograniczeń dolnych).
Przykład:
public <T extends Comparable<T>> T findMax(T[] array) {
T max = array[0];
for (T element : array) {
if (element.compareTo(max) > 0) {
max = element;
}
}
return max;
}
W tym przypadku <T extends Comparable<T>>
oznacza, że typ T
musi implementować interfejs Comparable<T>
.
Wywoływanie Metod Generycznych: Podczas wywoływania metody generycznej, kompilator zazwyczaj jest w stanie wywnioskować typ generyczny na podstawie kontekstu, ale można też jawnie podać typ generyczny.
Przykład:
Projekt W13, example18
package example18;
// //Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class ArrayAlg {
public static <T> T getMiddle(T... a) {
return a[a.length / 2];
}
}
package example18;
public class TestArrayAlg {
public static void main(String[] args) {
String[] words = {"ABC", "DEF", "GHI", "JKL", "MNO"};
String middle = ArrayAlg.getMiddle(words);
System.out.println(middle);
Integer[] numbers = {1, -2, 7, 8, 12};
Integer middle2 = ArrayAlg.getMiddle(numbers);
System.out.println(middle2);
System.out.println(ArrayAlg.getMiddle("ABC", "DEF", "GHI"));
System.out.println(ArrayAlg.getMiddle(3.4, 177.0, 3.14, -5.6, 177.1));
}
}
Projekt W13, example19
package example19;
public class Test19 {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
print(intArray);
print(doubleArray);
print(charArray);
}
public static <T> void print(T[] array) {
for (T t : array) {
System.out.println(t);
}
}
}
Projekt W13, example20
package example20;
import java.util.Optional;
public class Test20 {
public static void main(String[] args) {
System.out.println(foo("ABC"));
System.out.println(foo(123));
System.out.println(foo(3.14));
System.out.println(foo2(123));
System.out.println(foo2(3.14));
//System.out.println(foo2("ABC"));
System.out.println(Optional.ofNullable(foo3()));
System.out.println(Optional.ofNullable(foo4(0)));
}
public static <T> int foo(T arg){
return arg.hashCode();
}
public static <T> int foo2(T arg) {
if (arg instanceof Number) {
return (int) Math.pow(((Number) arg).doubleValue(), 2);
}
throw new IllegalArgumentException("Arg musi być liczbą");
}
public static <T> T foo3(){
return null;
}
public static <T> T foo4(int arg) {
if (arg == 0) {
return (T) Integer.valueOf(arg);
} else if (arg == 1) {
return (T) "String";
}
return (T) new Object();
}
}
package example21;
// //Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class ArrayAlg {
public static <T> T min(T... a) {
if (a == null || a.length == 0) {
return null;
}
T smallest = a[0];
for (int i = 1; i < a.length; i++) {
if (smallest.compareTo(a[i]) > 0) {
smallest = a[i];
}
}
return smallest;
}
}
Czy czegoś tu nie brak?
Projekt W13, example21
package example21;
// //Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class ArrayAlg {
public static <T extends Comparable<T>> T min(T... a) {
if (a == null || a.length == 0) {
return null;
}
T smallest = a[0];
for (int i = 1; i < a.length; i++) {
if (smallest.compareTo(a[i]) > 0) {
smallest = a[i];
}
}
return smallest;
}
}
package example21;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Person other) {
return Integer.compare(this.age, other.age);
}
@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + name + ",age=" + age + "]";
}
}
package example21;
public class TestPerson {
public static void main(String[] args) {
Double[] numbers = {1.0, 12.0, -3.0};
System.out.println(ArrayAlg.min(numbers));
Person[] people = {new Person("Jan", 12), new Person("Anna", 10), new Person("Piotr", 15)};
System.out.println(ArrayAlg.min(people));
}
}
<T extends typ_graniczny>
jest składnią używaną w programowaniu generycznym do określenia górnej granicy dla typu generycznego T
. Oznacza to, że T
musi być podtypem (klasą pochodną) klasy określonej jako typ_graniczny
lub sama być tym typem.
Wymazywanie typów (ang. type erasure) to proces stosowany w Javie w kontekście programowania generycznego, który zapewnia kompatybilność wsteczną z wcześniejszymi wersjami Javy, które nie obsługiwały generyków. Kiedy kod zawierający generyki jest kompilowany, kompilator usuwa (wymazuje) wszelkie informacje o typach generycznych, zastępując je ich ograniczeniami lub, jeśli takie nie istnieją, obiektem najbardziej ogólnym (często Object
).
Jak Działa Wymazywanie Typów?
Object
, jeśli brak jest ograniczeń. Na przykład, dla class Box<T>
, T
zostanie zastąpione przez Object
podczas kompilacji.List<String>
czy List<Integer>
w czasie wykonania.Wymazywanie typów ma kilka konsekwencji: - Brak Możliwości Przeciążania Metod: Metody różniące się jedynie typem generycznym nie mogą być przeciążone, ponieważ po wymazaniu będą miały ten sam sygnaturę.
Konieczność Rzutowania: W czasie wykonania trzeba czasami ręcznie rzutować obiekty na odpowiedni typ, co może prowadzić do błędów ClassCastException
.
Brak Możliwości Sprawdzenia Typu Generycznego w Runtime: Nie można używać refleksji do dokładnego ustalenia typu generycznego w czasie wykonania, ponieważ informacje te są wymazane.
// Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
jest wymazywany na:
public class Pair {
private Object first;
private Object second;
public Pair() {
first = null;
second = null;
}
public Pair(Object first, Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
public void setFirst(Object newValue) {
first = newValue;
}
public void setSecond(Object newValue) {
second = newValue;
}
}
public static <T extends Comparable<T>> T min(T... a) {
if (a == null || a.length == 0) {
return null;
}
T smallest = a[0];
for (int i = 1; i < a.length; i++) {
if (smallest.compareTo(a[i]) > 0) {
smallest = a[i];
}
}
return smallest;
}
jest wymazywany na:
Typy proste (ang. primitive types), takie jak int
, double
, char
, itd., nie mogą być używane jako typy generyczne. Wynika to z kilku powodów, głównie związanych z tym, jak generyki są implementowane w Javie oraz jak działają typy proste:
Object
.Object
w procesie wymazywania typów.Integer
dla int
, Double
dla double
itp.List<int>
, używa się List<Integer>
.Projekt W13, example22
package example22;
// Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
Termin “typ wieloznaczny” (ang. wildcard type) odnosi się do typów generycznych, które nie są dokładnie określone, czyli używają symbolu zapytania ?
jako zastępczego oznaczenia typu. Typy wieloznaczne pozwalają na większą elastyczność w definiowaniu i wykorzystywaniu generycznych struktur danych i metod, ponieważ mogą reprezentować szeroki zakres różnych typów.
Rodzaje Typów Wieloznacznych:
?
):
List<?>
może być listą dowolnego typu obiektów.? extends T
):
T
lub dowolnej jej podklasy. Na przykład, List<? extends Number>
może być listą obiektów typu Number
lub dowolnego typu, który jest podklasą Number
(jak Integer
czy Double
).? super T
):
T
lub dowolnej jej nadklasy. Na przykład, List<? super Integer>
może być listą obiektów typu Integer
lub dowolnego typu, który jest nadklasą Integer
(jak Number
czy Object
).Projekt W13, example23
package example23;
// Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
package example23;
public class Animal {
@Override
public String toString() {
return getClass().getSimpleName();
}
}
package example23;
public class Test23 {
public static void main(String[] args) {
Pair<Animal> animals = new Pair<>(new Animal(), new Animal());
printAnimals(animals);
Pair<Dog> dogs = new Pair<>(new Dog(), new Dog());
//printAnimals(dogs);
printAnimalsFix(animals);
printAnimalsFix(dogs);
printAnimalsFix2(animals);
printAnimalsFix2(dogs);
printAnimalsFix3(animals);
printAnimalsFix3(dogs);
}
public static void printAnimals(Pair<Animal> animals) {
System.out.println(animals.getFirst().toString() + " " + animals.getSecond().toString());
}
public static void printAnimalsFix(Pair<? extends Animal> animals) {
System.out.println(animals.getFirst().toString() + " " + animals.getSecond().toString());
}
public static void printAnimalsFix2(Pair<? super Dog> animals) {
System.out.println(animals.getFirst().toString() + " " + animals.getSecond().toString());
}
public static void printAnimalsFix3(Pair<?> animals) {
System.out.println(animals.getFirst().toString() + " " + animals.getSecond().toString());
}
}
Projekt W13, example24
package example24;
// Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
public class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
package example24;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
public void setName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
this.name = name;
}
@Override
public String toString() {
return getClass().getSimpleName() + ": name=" + name + ", age=" + age;
}
@Override
public int compareTo(Person o) {
int base = this.name.compareTo(o.name);
if (base != 0) {
return base;
}
return Integer.compare(this.age, o.age);
}
}
package example24;
public class Student extends Person implements Comparable<Person>{
private int studentId;
public Student(String name, int age, int studentId) {
super(name, age);
if (studentId <10000 || studentId > 999999) {
throw new IllegalArgumentException("Wrong student ID");
}
this.studentId = studentId;
}
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
if (studentId <10000 || studentId > 999999) {
throw new IllegalArgumentException("Wrong student ID");
}
this.studentId = studentId;
}
@Override
public String toString() {
return super.toString() + ", studentId=" + studentId;
}
@Override
public int compareTo(Person o) {
if (o instanceof Student) {
Student student = (Student) o;
int base = super.compareTo(student);
if (base != 0) {
return base;
}
return Integer.compare(this.studentId, student.studentId);
}
return super.compareTo(o);
}
}
package example24;
public class Test24 {
public static void main(String[] args) {
Person[] people = new Person[4];
people[0] = new Person("John", 20);
people[1] = new Person("John", 30);
people[2] = new Person("Adam", 20);
people[3] = new Person("Adam", 16);
System.out.println("Case 1");
Pair<Person> pair = minmaxOld(people);
System.out.println(pair.getFirst());
System.out.println(pair.getSecond());
Student[] students = new Student[4];
students[0] = new Student("John", 20, 125478);
students[1] = new Student("John", 30, 122278);
students[2] = new Student("Adam", 20, 125433);
students[3] = new Student("Adam", 16, 165478);
//Pair<Student> pair2 = minmaxBad(students); // to nie jest możliwe
System.out.println("Case 2");
Pair<Student> pair2 = minmax(students);
System.out.println(pair2.getFirst());
System.out.println(pair2.getSecond());
Person[] people2 = new Person[6];
people2[0] = new Person("John", 20);
people2[1] = new Person("John", 30);
people2[2] = new Person("Adam", 20);
people2[3] = new Student("John", 20, 125478);
people2[4] = new Student("John", 30, 122278);
people2[5] = new Student("Adam", 20, 125433);
System.out.println("Case 3");
Pair<Person> pair3 = minmaxOld(people2);
System.out.println(pair3.getFirst());
System.out.println(pair3.getSecond());
System.out.println("Case 4");
Pair<Person> pair4 = minmax(people2);
System.out.println(pair4.getFirst());
System.out.println(pair4.getSecond());
}
public static <T extends Comparable<T>> Pair<T> minmaxOld(T[] a) {
if (a == null || a.length == 0) {
return null;
}
T min = a[0];
T max = a[0];
for (int i=1; i<a.length; i++) {
if (min.compareTo(a[i]) > 0) {
min = a[i];
}
if (max.compareTo(a[i]) < 0) {
max = a[i];
}
}
return new Pair<>(min, max);
}
public static <T extends Comparable<? super T>> Pair<T> minmax(T[] a) {
if (a == null || a.length == 0) {
return null;
}
T min = a[0];
T max = a[0];
for (int i=1; i<a.length; i++) {
if (min.compareTo(a[i]) > 0) {
min = a[i];
}
if (max.compareTo(a[i]) < 0) {
max = a[i];
}
}
return new Pair<>(min, max);
}
}
Stwórz prostą klasę generyczną Box
, która może przechowywać obiekt dowolnego typu. Klasa powinna zawierać metodę set
, aby ustawić obiekt, oraz metodę get
, aby go pobrać.
Napisz generyczną metodę isEqual
, która przyjmuje dwa dowolne obiekty tego samego typu i zwraca true
, jeśli są one równe, w przeciwnym razie false
.
Stwórz klasę generyczną Counter<T>
, która będzie zliczać ilość dodanych elementów określonego typu. Klasa powinna mieć metodę add(T element)
, która dodaje element do wewnętrznej struktury, oraz metodę getCount()
, która zwraca liczbę dodanych elementów.
Napisz statyczną metodę generyczną swap
, która przyjmuje tablicę dowolnego typu i dwa indeksy, a następnie zamienia miejscami elementy w tej tablicy pod wskazanymi indeksami. Metoda powinna działać dla tablicy każdego typu. Przykładowe wywołanie metody: swap(myArray, 0, 2);
, gdzie myArray
to tablica typu Integer[]
lub dowolnego innego typu. Zabezpiecz metodę tak, aby nie można było jej wywołać z indeksami spoza zakresu tablicy, jak również dla null
i pustej tablicy (o zerowej liczbie elementów).
Napisz statyczną metodę generyczną maxValue
, która przyjmuje tablicę elementów typu generycznego T
, gdzie T
rozszerza Comparable<T>
. Metoda powinna zwracać największy element z tablicy. Upewnij się, że metoda nie akceptuje pustej tablicy (o zerowej liczbie elementów). Przetestuj metodę na tablicach zawierających różne typy porównywalnych obiektów, jak Integer
, Float
, czy String
. Stwórz klasę Vehicle
z polami model
i speed
, implementującą generyczny Comparable
, i przetestuj metodę maxValue
na tablicy obiektów Vehicle
.
W kontekście programowania obiektowego w Javie, kolekcja (ang. ‘collection’) odnosi się do struktury danych, która grupuje obiekty w pojedynczym zbiorniku. Java oferuje szeroki zestaw klas kolekcji w ramach Java Collections Framework, które pozwalają na przechowywanie, przetwarzanie i manipulację zbiorami danych w elastyczny i efektywny sposób.
Uwaga: w internecie można znaleźć misz masz własności, w szczególności pod kątem złożoności obliczeniowej. Warygodnym źródłem jest dokumentacha.
Książka w trakcie powstawania:
Maurice Naftalin, Philip Wadler, Java Generics and Collections, O’Reilly Media, Inc. - wydanie drugie planowane na czerwiec 2024, choć można znaleźć fragemty w internecie.
Ilustacji z książki: Cay S. Horstmann, Java. Podstawy. Wydanie XII , Wyd. Helion, 2021.
Iterator
Collection
ArrayList
LinkedList
HashSet
TreeSet
HashMap
TreeMap
Iterator
Generyczny interfejs Iterator<E>
jest fundamentalnym elementem Java Collections Framework, umożliwiającym przeglądanie elementów kolekcji, takich jak listy, zbiory (sets) czy kolejki (queues).
Metody:
boolean hasNext()
: Ta metoda sprawdza, czy w kolekcji są jeszcze jakieś elementy do przetworzenia. Zwraca true
, jeśli kolekcja posiada kolejne elementy.E next()
: Zwraca następny element z kolekcji. Gdy nie ma więcej elementów, rzucany jest wyjątek NoSuchElementException
.void remove()
: Usuwa z kolekcji ostatni element zwrócony przez metodę next()
. Metoda ta może rzucić wyjątek UnsupportedOperationException
, jeśli operacja usuwania nie jest wspierana przez daną kolekcję.forEachRemaining(Consumer<? super E> action)
: Służy do wykonania danej akcji dla każdego pozostałego elementu w iteracji, zaczynając od aktualnej pozycji iteratora.Collection
Interfejs Collection<E>
jest jednym z podstawowych interfejsów w Java Collections Framework i służy jako korzeń dla innych interfejsów kolekcji, takich jak List
, Set
, czy Queue
. Jest to generyczny interfejs, co oznacza, że można go parametryzować różnymi typami obiektów (reprezentowanymi przez E
).
Metody:
Interfejs Collection<E>
w Javie zawiera wiele metod, które są fundamentalne dla manipulowania i dostępu do kolekcji danych. Oto niektóre z najpopularniejszych i najczęściej używanych metod tego interfejsu:
add(E e)
: Dodaje określony element do kolekcji. Zwraca true
, jeśli kolekcja zmieniła się w wyniku wywołania tej metody.
addAll(Collection<? extends E> c)
: Dodaje wszystkie elementy z określonej kolekcji do bieżącej kolekcji. Zwraca true
, jeśli bieżąca kolekcja zmieniła się w wyniku wywołania tej metody.
clear()
: Usuwa wszystkie elementy z kolekcji. Po wykonaniu tej metody kolekcja jest pusta.
contains(Object o)
: Sprawdza, czy kolekcja zawiera określony element. Zwraca true
, jeśli kolekcja zawiera przynajmniej jedno wystąpienie określonego elementu.
containsAll(Collection<?> c)
: Sprawdza, czy kolekcja zawiera wszystkie elementy z określonej kolekcji.
isEmpty()
: Sprawdza, czy kolekcja jest pusta (nie zawiera żadnych elementów). Zwraca true
, jeśli kolekcja nie zawiera żadnych elementów.
iterator()
: Zwraca iterator do przeglądania elementów w kolekcji. Iterator pozwala na sekwencyjne przechodzenie przez elementy kolekcji.
remove(Object o)
: Usuwa jedno wystąpienie określonego elementu z kolekcji, jeśli istnieje. Zwraca true
, jeśli kolekcja zmieniła się w wyniku wywołania tej metody.
removeAll(Collection<?> c)
: Usuwa z tej kolekcji wszystkie jej elementy, które są zawarte w określonej kolekcji.
retainAll(Collection<?> c)
: Zachowuje tylko te elementy w kolekcji, które są zawarte w określonej kolekcji. Innymi słowy, usuwa z tej kolekcji wszystkie elementy, których nie ma w określonej kolekcji.
size()
: Zwraca liczbę elementów w kolekcji.
toArray()
: Zwraca tablicę zawierającą wszystkie elementy kolekcji.
Możliwość tworzenie algorytmów generycznych opartych na kolekcjach.
Projekt W13, example25
LinkedList
(lista powiązana)LinkedList<E>
w Javie jest implementacją listy powiązanej, która jest częścią Java Collection Framework. Jest to dynamiczna struktura danych, co oznacza, że może dynamicznie rosnąć i zmniejszać się, dodając lub usuwając elementy.
Implementacja: LinkedList
implementuje interfejsy List
, Deque
, i Queue
. Może więc działać jako lista, dwustronna kolejka (deque) lub kolejka (queue).
Węzły: Każdy element (węzeł) w LinkedList
przechowuje dane oraz referencje do poprzedniego i następnego elementu, co umożliwia łatwe dodawanie i usuwanie elementów.
Dostęp do elementów: Dostęp do elementów w LinkedList
jest sekwencyjny, co oznacza, że czas dostępu do elementów jest proporcjonalny do ich położenia.
Złożoność czasowa: Dodawanie/usuwanie na początku lub końcu listy ma złożoność O(1). Wyszukiwanie, dodawanie lub usuwanie elementów w środku listy ma złożoność O(n), gdzie n to liczba elementów w liście.
Użycie pamięci: Każdy element listy wiązanej wymaga dodatkowej pamięci na przechowywanie referencji do następnego i poprzedniego elementu, co czyni LinkedList
bardziej wymagającą pod względem pamięci w porównaniu z ArrayList
.
Metody: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/LinkedList.html
void add(int index, E element): Wstawia określony element na określonej pozycji na liście.
boolean add(E e): Dodaje określony element na końcu listy.
boolean addAll(int index, Collection<? extends E> c): Wstawia wszystkie elementy z określonej kolekcji do tej listy, zaczynając od określonej pozycji.
boolean addAll(Collection<? extends E> c): Dodaje wszystkie elementy z określonej kolekcji na końcu tej listy, w kolejności zwracanej przez iterator danej kolekcji.
void addFirst(E e): Wstawia określony element na początku listy.
void addLast(E e): Dodaje określony element na końcu listy.
void clear(): Usuwa wszystkie elementy z tej listy.
Object clone(): Zwraca płytką kopię tej listy LinkedList
.
boolean contains(Object o): Zwraca true
, jeśli lista zawiera określony element.
Iterator
E element(): Pobiera, ale nie usuwa, głowę (pierwszy element) tej listy.
E get(int index): Zwraca element na określonej pozycji na liście.
E getFirst(): Zwraca pierwszy element na liście.
E getLast(): Zwraca ostatni element na liście.
int indexOf(Object o): Zwraca indeks pierwszego wystąpienia określonego elementu na liście, lub -1, jeśli lista nie zawiera tego elementu.
int lastIndexOf(Object o): Zwraca indeks ostatniego wystąpienia określonego elementu na liście, lub -1, jeśli lista nie zawiera tego elementu.
ListIterator
boolean offer(E e): Dodaje określony element jako ogon (ostatni element) tej listy.
boolean offerFirst(E e): Wstawia określony element na początku tej listy.
boolean offerLast(E e): Wstawia określony element na końcu tej listy.
E peek(): Pobiera, ale nie usuwa, głowę (pierwszy element) tej listy.
E peekFirst(): Pobiera, ale nie usuwa, pierwszy element tej listy lub zwraca null
, jeśli lista jest pusta.
E peekLast(): Pobiera, ale nie usuwa, ostatni element tej listy lub zwraca null
, jeśli lista jest pusta.
E poll(): Pobiera i usuwa głowę (pierwszy element) tej listy.
E pollFirst(): Pobiera i usuwa pierwszy element tej listy, lub zwraca null
, jeśli lista jest pusta.
E pollLast(): Pobiera i usuwa ostatni element tej listy, lub zwraca null
, jeśli lista jest pusta.
E pop(): Usuwa i zwraca element ze stosu reprezentowanego przez tę listę.
void push(E e): Wstawia element na stos reprezentowany przez tę listę.
E remove(): Pobiera i usuwa głowę (pierwszy element) tej listy.
E remove(int index): Usuwa element na określonej pozycji na liście.
boolean remove(Object o): Usuwa pierwsze wystąpienie określonego elementu z tej listy, jeśli jest obecny.
E removeFirst(): Usuwa i zwraca pierwszy element z tej listy.
boolean removeFirstOccurrence(Object o): Usuwa pierwsze wystąpienie określonego elementu na tej liście (podczas przeglądania listy od głowy do ogona).
E removeLast(): Usuwa i zwraca ostatni element z tej listy.
boolean removeLastOccurrence(Object o): Usuwa ostatnie wystąpienie określonego elementu na tej liście (podczas przeglądania listy od głowy do ogona).
LinkedList
E set(int index, E element): Zastępuje element na określonej pozycji na liście określonym elementem.
int size(): Zwraca liczbę elementów na tej liście.
SpliteratorSpliterator
po elementach tej listy.
Object[] toArray(): Zwraca tablicę zawierającą wszystkie elementy tej listy w odpowiedniej kolejności (od pierwszego do ostatniego elementu).
Projekt W13, example26
HashSet
(zbiór mieszający)HashSet<E>
to implementacja zbioru, która jest częścią Java Collections Framework. Jest to kolekcja, która przechowuje unikalne elementy, nie dopuszczając duplikatów.
Unikalność: HashSet
przechowuje tylko unikalne elementy. Próba dodania duplikatu nie spowoduje błędu, ale element nie zostanie dodany.
Brak kolejności: Elementy w HashSet
nie są przechowywane w żadnej określonej kolejności. Kolejność elementów może się różnić przy każdym uruchomieniu programu.
Szybkość działania: HashSet
zapewnia stały czas potrzebny do operacji dodawania, usuwania i sprawdzania, czy element istnieje, co sprawia, że jest bardzo wydajny.
Null: HashSet
pozwala na przechowywanie maksymalnie jednego elementu null
.
Implementacja: HashSet
jest zaimplementowany na bazie tablicy mieszającej (HashMap
), gdzie klucze to elementy zbioru, a wartości są obiektami-pustymi miejscami.
Brak gwarancji kolejności: Kolejność elementów w HashSet
może się zmieniać w miarę dodawania lub usuwania elementów.
Metody: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/HashSet.html
boolean add(E e): Dodaje określony element do tego zbioru, jeśli jeszcze się w nim nie znajduje.
void clear(): Usuwa wszystkie elementy z tego zbioru.
Object clone(): Zwraca płytką kopię tej instancji HashSet
: same elementy nie są klonowane.
boolean contains(Object o): Zwraca true
, jeśli ten zbiór zawiera określony element.
boolean isEmpty(): Zwraca true
, jeśli ten zbiór nie zawiera żadnych elementów.
Iterator
static HashSet
odpowiedni dla oczekiwanej liczby elementów.
boolean remove(Object o): Usuwa określony element z tego zbioru, jeśli jest obecny.
int size(): Zwraca liczbę elementów w tym zbiorze (jego moc).
SpliteratorSpliterator
po elementach tego zbioru.
Object[] toArray(): Zwraca tablicę zawierającą wszystkie elementy tej kolekcji.
Projekt W13, example27
TreeSet
(zbiór drzewiasty)TreeSet<E>
to implementacja zbioru oparta na drzewie czerwono-czarnym, będąca częścią Java Collections Framework. Jest to posortowana i automatycznie sortująca się kolekcja unikalnych elementów.
Sortowanie: Elementy w TreeSet
są zawsze posortowane według naturalnego porządku lub według Comparatora dostarczonego przy tworzeniu zbioru. To oznacza, że elementy są automatycznie sortowane w momencie ich dodawania.
Unikalność: Podobnie jak HashSet
, TreeSet
przechowuje tylko unikalne elementy, nie dopuszczając duplikatów.
Wykonanie: Dzięki strukturze drzewa czerwono-czarnego, operacje takie jak wyszukiwanie, dodawanie i usuwanie elementów mają złożoność czasową logarytmiczną O(log n), co jest bardziej efektywne niż liniowa złożoność niektórych innych struktur danych dla dużych zestawów danych.
Null: TreeSet
zwykle nie akceptuje wartości null
jako elementów. Próba dodania null
może skutkować NullPointerException
, w zależności od użytego Comparatora.
Iteracja: Iteracja przez elementy TreeSet
odbywa się w uporządkowany sposób, co jest korzystne, gdy potrzebna jest uporządkowana prezentacja danych.
Metody: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/TreeSet.html
boolean add(E e): Dodaje określony element do tego zbioru, jeśli jeszcze się w nim nie znajduje.
boolean addAll(Collection<? extends E> c): Dodaje wszystkie elementy z określonej kolekcji do tego zbioru.
void addFirst(E e): Rzuca wyjątek UnsupportedOperationException
.
void addLast(E e): Rzuca wyjątek UnsupportedOperationException
.
E ceiling(E e): Zwraca najmniejszy element w tym zbiorze większy lub równy podanemu elementowi, lub null
, jeśli taki element nie istnieje.
void clear(): Usuwa wszystkie elementy z tego zbioru.
Object clone(): Zwraca płytką kopię tej instancji TreeSet
.
Comparator<? super E> comparator(): Zwraca komparator używany do porządkowania elementów w tym zbiorze, lub null
, jeśli zbiór używa naturalnego porządkowania swoich elementów.
boolean contains(Object o): Zwraca true
, jeśli ten zbiór zawiera określony element.
Iterator
NavigableSet
E first(): Zwraca pierwszy (najniższy) element aktualnie w tym zbiorze.
E floor(E e): Zwraca największy element w tym zbiorze mniejszy lub równy podanemu elementowi, lub null
, jeśli taki element nie istnieje.
SortedSet
NavigableSettrue
) toElement.
E higher(E e): Zwraca najmniejszy element w tym zbiorze ściśle większy niż podany element, lub null
, jeśli taki element nie istnieje.
boolean isEmpty(): Zwraca true
, jeśli ten zbiór nie zawiera żadnych elementów.
Iterator
E last(): Zwraca ostatni (najwyższy) element aktualnie w tym zbiorze.
E lower(E e): Zwraca największy element w tym zbiorze ściśle mniejszy niż podany element, lub null
, jeśli taki element nie istnieje.
E pollFirst(): Pobiera i usuwa pierwszy (najniższy) element, lub zwraca null
, jeśli ten zbiór jest pusty.
E pollLast(): Pobiera i usuwa ostatni (najwyższy) element, lub zwraca null
, jeśli ten zbiór jest pusty.
boolean remove(Object o): Usuwa określony element z tego zbioru, jeśli jest obecny.
int size(): Zwraca liczbę elementów w tym zbiorze (jego moc).
SpliteratorSpliterator
po elementach tego zbioru.
NavigableSet
SortedSet
SortedSet
NavigableSettrue
) fromElement.
Projekt W13, example28
HashMap
(mapa mieszająca)HashMap<K,V>
w Javie to kolekcja, która przechowuje pary klucz-wartość. Jest to część Java Collections Framework i oferuje efektywne sposoby przechowywania i dostępu do danych.
Struktura klucz-wartość: Każdy element w HashMap
składa się z klucza (unikalnego identyfikatora) i przypisanej mu wartości.
Szybki dostęp do danych: Dzięki funkcji mieszającej (hashing), HashMap
pozwala na bardzo szybkie wyszukiwanie wartości na podstawie klucza. Operacje takie jak wstawianie, wyszukiwanie lub usuwanie elementów mają zazwyczaj stałą złożoność czasową O(1).
Unikalność kluczy: W HashMap
każdy klucz musi być unikalny. Próba wstawienia duplikatu klucza spowoduje nadpisanie starej wartości przez nową.
Null jako klucz i wartość: HashMap
pozwala na użycie null
jako klucza (ale tylko raz, ponieważ klucze są unikalne) oraz null
jako wartości.
Nieuporządkowana: Kolejność przechowywania par klucz-wartość w HashMap
nie jest gwarantowana i może się zmieniać z czasem, zwłaszcza po operacjach, które zmieniają rozmiar mapy, np. po dodaniu nowych elementów.
Metody: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/HashMap.html
void clear(): Usuwa wszystkie mapowania z tej mapy.
Object clone(): Zwraca płytką kopię tej instancji HashMap
: klucze i wartości same w sobie nie są klonowane.
V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction): Próbuje obliczyć mapowanie dla określonego klucza i jego aktualnie mapowanej wartości (lub null
, jeśli mapowanie nie istnieje).
V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction): Jeśli określony klucz nie jest jeszcze skojarzony z wartością (lub jest mapowany na null
), próbuje obliczyć jego wartość za pomocą podanej funkcji mapującej i wprowadza ją do tej mapy, chyba że wynik jest null
.
V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction): Jeśli wartość dla określonego klucza jest obecna i nie jest null
, próbuje obliczyć nowe mapowanie na podstawie klucza i jego aktualnie mapowanej wartości.
boolean containsKey(Object key): Zwraca true
, jeśli ta mapa zawiera mapowanie dla określonego klucza.
boolean containsValue(Object value): Zwraca true
, jeśli ta mapa mapuje jeden lub więcej kluczy na określoną wartość.
Set<Map.Entry<K,V>> entrySet(): Zwraca widok zbioru mapowań zawartych w tej mapie.
V get(Object key): Zwraca wartość, do której mapowany jest określony klucz, lub null
, jeśli ta mapa nie zawiera mapowania dla klucza.
boolean isEmpty(): Zwraca true
, jeśli ta mapa nie zawiera żadnych mapowań klucz-wartość.
Set
V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction): Jeśli określony klucz nie jest już skojarzony z wartością lub jest skojarzony z null
, kojarzy go z podaną wartością niebędącą null
.
static <K,V> HashMap<K,V> newHashMap(int numMappings): Tworzy nową, pustą HashMap
odpowiednią dla oczekiwanej liczby mapowań.
V put(K key, V value): Kojarzy określoną wartość z określonym kluczem w tej mapie.
void putAll(Map<? extends K,? extends V> m): Kopiuje wszystkie mapowania z określonej mapy do tej mapy.
V remove(Object key): Usuwa mapowanie dla określonego klucza z tej mapy, jeśli jest obecne.
int size(): Zwraca liczbę mapowań klucz-wartość w tej mapie.
Collection
Projekt W13, example29
Projekt W13, example30
TreeMap
(mapa drzewiasta)TreeMap<K,V>
w Javie to posortowana mapa bazująca na czerwono-czarnym drzewie. Jest to część Java Collections Framework i działa jako mapa klucz-wartość, gdzie każdy klucz jest unikalny.
Automatyczne sortowanie: Klucze w TreeMap
są sortowane według naturalnego porządku (jeśli implementują interfejs Comparable
) lub według Comparatora
przekazanego przy tworzeniu mapy. Dzięki temu, kiedy iterujesz po kluczach, są one zwracane w posortowanej kolejności.
Wykonanie: Operacje wyszukiwania, wstawiania i usuwania mają logarytmiczną złożoność czasową O(log n), co sprawia, że TreeMap
jest wydajna dla dużych zbiorów danych.
Null jako klucz: Standardowo TreeMap
nie akceptuje null
jako klucza (w przeciwieństwie do HashMap
), szczególnie gdy używa naturalnego porządkowania, ponieważ null
nie może być porównywany.
Dostęp do pierwszego i ostatniego elementu: TreeMap
zapewnia szybki dostęp do pierwszego (najmniejszego) i ostatniego (największego) klucza.
Widoki: TreeMap
oferuje metody takie jak headMap
, tailMap
i subMap
, które pozwalają na tworzenie widoków określonych zakresów mapy.
Metody: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/TreeMap.html
Map.Entry<K,V> ceilingEntry(K key): Zwraca mapowanie klucz-wartość związane z najmniejszym kluczem większym lub równym podanemu kluczowi, lub null
, jeśli taki klucz nie istnieje.
K ceilingKey(K key): Zwraca najmniejszy klucz większy lub równy podanemu kluczowi, lub null
, jeśli taki klucz nie istnieje.
void clear(): Usuwa wszystkie mapowania z tej mapy.
Object clone(): Zwraca płytką kopię tej instancji TreeMap
.
Comparator<? super K> comparator(): Zwraca komparator używany do porządkowania kluczy w tej mapie, lub null
, jeśli mapa używa naturalnego porządkowania swoich kluczy.
V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction): Próbuje obliczyć mapowanie dla określonego klucza i jego aktualnie mapowanej wartości (lub null
, jeśli mapowanie nie istnieje).
V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction): Jeśli określony klucz nie jest już skojarzony z wartością (lub jest mapowany na null
), próbuje obliczyć jego wartość za pomocą podanej funkcji mapującej i wprowadza ją do tej mapy, chyba że wynik jest null
.
V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction): Jeśli wartość dla określonego klucza jest obecna i nie jest null
, próbuje obliczyć nowe mapowanie na podstawie klucza i jego aktualnie mapowanej wartości.
boolean containsKey(Object key): Zwraca true
, jeśli ta mapa zawiera mapowanie dla określonego klucza.
boolean containsValue(Object value): Zwraca true
, jeśli ta mapa mapuje jeden lub więcej kluczy na określoną wartość.
NavigableSetNavigableSet
kluczy zawartych w tej mapie.
NavigableMap<K,V> descendingMap(): Zwraca widok w odwrotnej kolejności mapowań zawartych w tej mapie.
Set<Map.Entry<K,V>> entrySet(): Zwraca widok zbioru mapowań zawartych w tej mapie.
Map.Entry<K,V> firstEntry(): Zwraca mapowanie klucz-wartość związane z najmniejszym kluczem w tej mapie, lub null
, jeśli mapa jest pusta.
K firstKey(): Zwraca pierwszy (najniższy) klucz obecnie w tej mapie.
Map.Entry<K,V> floorEntry(K key): Zwraca mapowanie klucz-wartość związane z największym kluczem mniejszym lub równym podanemu kluczowi, lub null
, jeśli taki klucz nie istnieje.
K floorKey(K key): Zwraca największy klucz mniejszy lub równy podanemu kluczowi, lub null
, jeśli taki klucz nie istnieje.
V get(Object key): Zwraca wartość, do której mapowany jest określony klucz, lub null
, jeśli ta mapa nie zawiera mapowania dla klucza.
SortedMap<K,V> headMap(K toKey): Zwraca widok części tej mapy, której klucze są ściśle mniejsze niż toKey.
NavigableMap<K,V> headMap(K toKey, boolean inclusive): Zwraca widok części tej mapy, której klucze są mniejsze niż (lub równe, jeśli inclusive jest true
) toKey.
Map.Entry<K,V> higherEntry(K key): Zwraca map
owanie klucz-wartość związane z najmniejszym kluczem ściśle większym niż podany klucz, lub null
, jeśli taki klucz nie istnieje.
K higherKey(K key): Zwraca najmniejszy klucz ściśle większy niż podany klucz, lub null
, jeśli taki klucz nie istnieje.
Set
Map.Entry<K,V> lastEntry(): Zwraca mapowanie klucz-wartość związane z największym kluczem w tej mapie, lub null
, jeśli mapa jest pusta.
K lastKey(): Zwraca ostatni (najwyższy) klucz obecnie w tej mapie.
Map.Entry<K,V> lowerEntry(K key): Zwraca mapowanie klucz-wartość związane z największym kluczem ściśle mniejszym niż podany klucz, lub null
, jeśli taki klucz nie istnieje.
K lowerKey(K key): Zwraca największy klucz ściśle mniejszy niż podany klucz, lub null
, jeśli taki klucz nie istnieje.
V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction): Jeśli określony klucz nie jest już skojarzony z wartością lub jest skojarzony z null
, kojarzy go z podaną wartością niebędącą null
.
NavigableSetNavigableSet
kluczy zawartych w tej mapie.
Map.Entry<K,V> pollFirstEntry(): Usuwa i zwraca mapowanie klucz-wartość związane z najmniejszym kluczem w tej mapie, lub null
, jeśli mapa jest pusta.
Map.Entry<K,V> pollLastEntry(): Usuwa i zwraca mapowanie klucz-wartość związane z największym kluczem w tej mapie, lub null
, jeśli mapa jest pusta.
V put(K key, V value): Kojarzy określoną wartość z określonym kluczem w tej mapie.
void putAll(Map<? extends K,? extends V> map): Kopiuje wszystkie mapowania z określonej mapy do tej mapy.
V putFirst(K k, V v): Rzuca wyjątek UnsupportedOperationException
.
V putLast(K k, V v): Rzuca wyjątek UnsupportedOperationException
.
V remove(Object key): Usuwa mapowanie dla tego klucza z tej mapy TreeMap
, jeśli jest obecne.
int size(): Zwraca liczbę mapowań klucz-wartość w tej mapie.
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive): Zwraca widok części tej mapy, której klucze mieszczą się w zakresie od fromKey do toKey.
SortedMap<K,V> subMap(K fromKey, K toKey): Zwraca widok części tej mapy, której klucze mieszczą się w zakresie od fromKey, włącznie, do toKey, wyłącznie.
SortedMap<K,V> tailMap(K fromKey): Zwraca widok części tej mapy, której klucze są większe lub równe fromKey.
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive): Zwraca widok części tej mapy, której klucze są większe niż (lub równe, jeśli inclusive jest true
) fromKey.
Collection
Projekt W13, example31
Projekt W13, example32
Collections
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collections.html
Klasa Collections
w Javie pełni rolę narzędzia pomocniczego (utility class) dla kolekcji w Java Collections Framework. Zawiera ona statyczne metody, które działają na lub zwracają kolekcje. Jest to klasa czysto statyczna, co oznacza, że nie jest przeznaczona do tworzenia instancji (obiektów), lecz służy jako zbiór narzędzi dla różnych operacji na kolekcjach.