컬렉션 프레임워크
Il 컬렉션 프레임워크 Java는 통합 아키텍처입니다. 객체 그룹을 표현하고 조작합니다. 인터페이스를 제공하며, 데이터를 효율적으로 관리하기 위한 구현 및 알고리즘.
무엇을 배울 것인가
- 컬렉션 인터페이스 계층
- 목록: ArrayList 및 LinkedList
- 세트: HashSet, TreeSet 및 LinkedHashSet
- 지도: HashMap, TreeMap 및 LinkedHashMap
- 큐와 데크
- 컬렉션 알고리즘 및 유틸리티
컬렉션 계층 구조
주요 인터페이스
| 인터페이스 | 설명 | 구현 |
|---|---|---|
| 수집 | 루트 인터페이스 | - |
| 목록 | 중복된 순서가 있는 시퀀스 | 배열리스트, 링크드리스트 |
| 세트 | 독특한 요소 | 해시세트, 트리세트 |
| 대기줄 | FIFO 대기열 | 링크드리스트, 우선순위큐 |
| 지도 | 키-값 쌍 | 해시맵, 트리맵 |
Iterable
|
Collection
/ | \
List Set Queue
| | |
ArrayList HashSet LinkedList
LinkedList TreeSet PriorityQueue
Map (separata)
|
HashMap TreeMap
목록 - 정렬된 목록
List 항목을 삽입 순서로 유지
중복을 허용합니다. 색인이 생성되어 있습니다(위치별 액세스).
배열목록
import java.util.ArrayList;
import java.util.List;
public class RegistroStudenti {
public static void main(String[] args) {
// Creazione lista
List<String> studenti = new ArrayList<>();
// Aggiunta elementi
studenti.add("Mario Rossi");
studenti.add("Laura Bianchi");
studenti.add("Giuseppe Verdi");
studenti.add(1, "Anna Neri"); // Inserisce in posizione 1
// Accesso per indice
String primo = studenti.get(0); // "Mario Rossi"
String secondo = studenti.get(1); // "Anna Neri"
// Dimensione
int numStudenti = studenti.size(); // 4
// Modifica elemento
studenti.set(0, "Marco Rossi");
// Ricerca
boolean presente = studenti.contains("Laura Bianchi"); // true
int posizione = studenti.indexOf("Giuseppe Verdi"); // 3
// Rimozione
studenti.remove("Anna Neri"); // per valore
studenti.remove(0); // per indice
// Iterazione
for (String studente : studenti) {
System.out.println(studente);
}
// Iterazione con indice
for (int i = 0; i < studenti.size(); i++) {
System.out.println((i + 1) + ". " + studenti.get(i));
}
}
}
링크드리스트
import java.util.LinkedList;
import java.util.List;
public class CodaEsami {
public static void main(String[] args) {
LinkedList<String> coda = new LinkedList<>();
// Operazioni specifiche LinkedList
coda.addFirst("Studente urgente"); // In testa
coda.addLast("Studente normale"); // In coda
coda.add("Altro studente"); // In coda
// Accesso primi/ultimi
String primo = coda.getFirst();
String ultimo = coda.getLast();
String primoPeek = coda.peekFirst(); // Non rimuove
// Rimozione primi/ultimi
String rimossoPrimo = coda.removeFirst();
String rimossoUltimo = coda.removeLast();
// Uso come Stack (LIFO)
coda.push("Nuovo in cima");
String estratto = coda.pop();
// Uso come Queue (FIFO)
coda.offer("Nuovo in coda");
String servito = coda.poll();
}
}
ArrayList 대 LinkedList
| 작업 | 배열목록 | 링크드리스트 |
|---|---|---|
| get(인덱스) | O(1) - 빠름 | O(n) - 느림 |
| 추가(요소) | O(1) 감가상각됨 | 오(1) |
| 추가(0, 요소) | O(n) - 느림 | O(1) - 빠름 |
| 제거(0) | O(n) - 느림 | O(1) - 빠름 |
| 메모리 | 오버헤드 감소 | 추가 오버헤드(노드) |
권하다: ArrayList를 기본값으로 사용하고 LinkedList는 빈번한 오버헤드 삽입/제거에만 사용합니다.
세트 - 고유 세트
Set 중복을 허용하지 않습니다. 필요할 때 이상적입니다.
요소의 고유성을 보장합니다.
해시세트
import java.util.HashSet;
import java.util.Set;
public class CorsiUnici {
public static void main(String[] args) {
Set<String> corsiFrequentati = new HashSet<>();
// Aggiunta elementi
corsiFrequentati.add("Programmazione");
corsiFrequentati.add("Database");
corsiFrequentati.add("Reti");
corsiFrequentati.add("Programmazione"); // Duplicato ignorato!
System.out.println(corsiFrequentati.size()); // 3
// Verifica presenza
if (corsiFrequentati.contains("Database")) {
System.out.println("Corso già frequentato");
}
// Rimozione
corsiFrequentati.remove("Reti");
// Iterazione (ordine NON garantito)
for (String corso : corsiFrequentati) {
System.out.println(corso);
}
// Operazioni insiemistiche
Set<String> nuoviCorsi = new HashSet<>();
nuoviCorsi.add("AI");
nuoviCorsi.add("Database");
// Unione
Set<String> tutti = new HashSet<>(corsiFrequentati);
tutti.addAll(nuoviCorsi);
// Intersezione
Set<String> comuni = new HashSet<>(corsiFrequentati);
comuni.retainAll(nuoviCorsi);
// Differenza
Set<String> soloVecchi = new HashSet<>(corsiFrequentati);
soloVecchi.removeAll(nuoviCorsi);
}
}
TreeSet 및 LinkedHashSet
import java.util.TreeSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class TipiSet {
public static void main(String[] args) {
// TreeSet: ordinato automaticamente
Set<Integer> voti = new TreeSet<>();
voti.add(28);
voti.add(30);
voti.add(24);
voti.add(27);
System.out.println(voti); // [24, 27, 28, 30] - ordinato!
// Metodi specifici TreeSet
TreeSet<Integer> votiTree = new TreeSet<>(voti);
Integer minimo = votiTree.first(); // 24
Integer massimo = votiTree.last(); // 30
Integer inferiore = votiTree.lower(28); // 27 (strettamente <)
Integer superiore = votiTree.higher(28); // 30 (strettamente >)
// Subset
Set<Integer> medi = votiTree.subSet(25, 29); // [27, 28]
// LinkedHashSet: mantiene ordine di inserimento
Set<String> ordineIscrizione = new LinkedHashSet<>();
ordineIscrizione.add("Mario");
ordineIscrizione.add("Anna");
ordineIscrizione.add("Luigi");
// Iterazione nell'ordine di inserimento
for (String nome : ordineIscrizione) {
System.out.println(nome); // Mario, Anna, Luigi
}
}
}
비교 세트
| 유형 | 주문하다 | 성능 | 일반적인 사용 |
|---|---|---|---|
| 해시세트 | 아무도 | 오(1) | 최대 속도 |
| 트리세트 | 자연산/비교자 | O(로그 n) | 정렬된 요소 |
| LinkedHashSet | 삽입 | 오(1) | 주문 보존 |
맵 - 키-값 쌍
Map 고유 키를 값과 연결합니다. 구조에요
빠른 조회 및 사전에 가장 많이 사용되는 데이터입니다.
해시맵
import java.util.HashMap;
import java.util.Map;
public class RegistroVoti {
public static void main(String[] args) {
// Mappa studente -> voto
Map<String, Integer> voti = new HashMap<>();
// Inserimento
voti.put("Mario Rossi", 28);
voti.put("Laura Bianchi", 30);
voti.put("Giuseppe Verdi", 25);
// Accesso
Integer votoMario = voti.get("Mario Rossi"); // 28
Integer votoAssente = voti.get("Inesistente"); // null
// getOrDefault: evita null
Integer votoSicuro = voti.getOrDefault("Inesistente", 0);
// Verifica presenza
if (voti.containsKey("Laura Bianchi")) {
System.out.println("Laura è registrata");
}
if (voti.containsValue(30)) {
System.out.println("Qualcuno ha preso 30!");
}
// Aggiornamento
voti.put("Mario Rossi", 29); // Sovrascrive
// putIfAbsent: inserisce solo se assente
voti.putIfAbsent("Mario Rossi", 18); // Non cambia (già presente)
// Rimozione
voti.remove("Giuseppe Verdi");
voti.remove("Laura Bianchi", 30); // Rimuove solo se valore corrisponde
// Dimensione
int numStudenti = voti.size();
boolean vuota = voti.isEmpty();
}
}
Map<String, Integer> voti = new HashMap<>();
voti.put("Mario", 28);
voti.put("Laura", 30);
voti.put("Giuseppe", 25);
// Iterazione su chiavi
for (String studente : voti.keySet()) {
System.out.println(studente);
}
// Iterazione su valori
for (Integer voto : voti.values()) {
System.out.println(voto);
}
// Iterazione su coppie (Entry) - più efficiente
for (Map.Entry<String, Integer> entry : voti.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// forEach con lambda (Java 8+)
voti.forEach((studente, voto) ->
System.out.println(studente + " ha preso " + voto)
);
TreeMap 및 LinkedHashMap
import java.util.TreeMap;
import java.util.LinkedHashMap;
public class TipiMap {
public static void main(String[] args) {
// TreeMap: chiavi ordinate
TreeMap<String, Integer> alfabetico = new TreeMap<>();
alfabetico.put("Zeta", 1);
alfabetico.put("Alfa", 2);
alfabetico.put("Beta", 3);
// Iterazione in ordine alfabetico
for (String key : alfabetico.keySet()) {
System.out.println(key); // Alfa, Beta, Zeta
}
// Metodi navigazione
String prima = alfabetico.firstKey(); // "Alfa"
String ultima = alfabetico.lastKey(); // "Zeta"
String inferiore = alfabetico.lowerKey("Beta"); // "Alfa"
// LinkedHashMap: ordine di inserimento
LinkedHashMap<String, Integer> ordinato = new LinkedHashMap<>();
ordinato.put("Primo", 1);
ordinato.put("Secondo", 2);
ordinato.put("Terzo", 3);
// Mantiene ordine di inserimento
for (String key : ordinato.keySet()) {
System.out.println(key); // Primo, Secondo, Terzo
}
}
}
큐와 데크
Queue FIFO(선입선출) 대기열을 나타냅니다.
Deque 그것은 양면 꼬리이다.
import java.util.Queue;
import java.util.LinkedList;
import java.util.PriorityQueue;
public class GestioneCode {
public static void main(String[] args) {
// Coda FIFO con LinkedList
Queue<String> codaSportello = new LinkedList<>();
// offer: aggiunge in coda
codaSportello.offer("Cliente 1");
codaSportello.offer("Cliente 2");
codaSportello.offer("Cliente 3");
// peek: guarda primo senza rimuovere
String prossimo = codaSportello.peek(); // "Cliente 1"
// poll: rimuove e restituisce primo
String servito = codaSportello.poll(); // "Cliente 1"
System.out.println("Servito: " + servito);
// PriorityQueue: ordine per priorità
Queue<Integer> priorità = new PriorityQueue<>();
priorità.offer(30);
priorità.offer(10);
priorità.offer(20);
// Estrae in ordine di priorità (naturale = crescente)
while (!priorità.isEmpty()) {
System.out.println(priorità.poll()); // 10, 20, 30
}
// PriorityQueue con ordine personalizzato
Queue<String> perLunghezza = new PriorityQueue<>(
(a, b) -> a.length() - b.length()
);
perLunghezza.offer("lungo");
perLunghezza.offer("xx");
perLunghezza.offer("medio");
while (!perLunghezza.isEmpty()) {
System.out.println(perLunghezza.poll()); // xx, lungo, medio
}
}
}
import java.util.Deque;
import java.util.ArrayDeque;
public class CodaDoppia {
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();
// Operazioni in testa
deque.addFirst("A");
deque.offerFirst("B");
// Operazioni in coda
deque.addLast("C");
deque.offerLast("D");
// Stato: [B, A, C, D]
// Rimozione da testa
String primo = deque.removeFirst(); // "B"
String primoPoll = deque.pollFirst(); // "A"
// Rimozione da coda
String ultimo = deque.removeLast(); // "D"
String ultimoPoll = deque.pollLast(); // "C"
// Uso come Stack (LIFO)
Deque<String> stack = new ArrayDeque<>();
stack.push("Primo"); // In cima
stack.push("Secondo");
stack.push("Terzo");
while (!stack.isEmpty()) {
System.out.println(stack.pop()); // Terzo, Secondo, Primo
}
}
}
컬렉션 클래스의 알고리즘
수업 Collections 정적 메소드 제공
컬렉션에 대한 일반적인 작업을 위해.
import java.util.*;
public class UtilityCollections {
public static void main(String[] args) {
List<Integer> voti = new ArrayList<>(
Arrays.asList(25, 30, 28, 24, 27, 30)
);
// Ordinamento
Collections.sort(voti);
System.out.println(voti); // [24, 25, 27, 28, 30, 30]
// Ordinamento inverso
Collections.sort(voti, Collections.reverseOrder());
System.out.println(voti); // [30, 30, 28, 27, 25, 24]
// Ricerca binaria (lista deve essere ordinata!)
Collections.sort(voti);
int indice = Collections.binarySearch(voti, 27);
// Min e Max
int minimo = Collections.min(voti); // 24
int massimo = Collections.max(voti); // 30
// Frequenza
int cont30 = Collections.frequency(voti, 30); // 2
// Mescolare (shuffle)
Collections.shuffle(voti);
// Invertire
Collections.reverse(voti);
// Riempire
Collections.fill(voti, 0); // Tutti a 0
// Scambiare elementi
Collections.swap(voti, 0, 1);
// Rotazione
List<String> lista = new ArrayList<>(
Arrays.asList("A", "B", "C", "D")
);
Collections.rotate(lista, 1); // [D, A, B, C]
Collections.rotate(lista, -1); // [A, B, C, D]
// Liste immutabili
List<String> immutabile = Collections.unmodifiableList(lista);
// immutabile.add("X"); // UnsupportedOperationException!
// Lista vuota immutabile
List<String> vuota = Collections.emptyList();
// Singleton (lista con un elemento)
List<String> singolo = Collections.singletonList("Unico");
}
}
전체 예: 코스 관리 시스템
package scuola;
import java.util.*;
public class Corso {
private String nome;
private String docente;
private int maxStudenti;
private Set<String> studentiIscritti;
private Map<String, List<Integer>> votiStudenti;
public Corso(String nome, String docente, int maxStudenti) {
this.nome = nome;
this.docente = docente;
this.maxStudenti = maxStudenti;
this.studentiIscritti = new LinkedHashSet<>();
this.votiStudenti = new HashMap<>();
}
public boolean iscrivi(String studente) {
if (studentiIscritti.size() >= maxStudenti) {
System.out.println("Corso pieno!");
return false;
}
if (studentiIscritti.contains(studente)) {
System.out.println(studente + " già iscritto!");
return false;
}
studentiIscritti.add(studente);
votiStudenti.put(studente, new ArrayList<>());
return true;
}
public void registraVoto(String studente, int voto) {
if (!studentiIscritti.contains(studente)) {
System.out.println(studente + " non iscritto!");
return;
}
if (voto < 18 || voto > 30) {
System.out.println("Voto non valido");
return;
}
votiStudenti.get(studente).add(voto);
}
public double calcolaMedia(String studente) {
List<Integer> voti = votiStudenti.get(studente);
if (voti == null || voti.isEmpty()) {
return 0;
}
return voti.stream()
.mapToInt(Integer::intValue)
.average()
.orElse(0);
}
public Map<String, Double> classificaStudenti() {
Map<String, Double> classifica = new TreeMap<>();
for (String studente : studentiIscritti) {
classifica.put(studente, calcolaMedia(studente));
}
return classifica;
}
public List<String> getStudentiOrdinatiPerMedia() {
List<String> ordinati = new ArrayList<>(studentiIscritti);
ordinati.sort((s1, s2) ->
Double.compare(calcolaMedia(s2), calcolaMedia(s1))
);
return ordinati;
}
public void stampaRiepilogo() {
System.out.println("╔══════════════════════════════════════╗");
System.out.println("║ Corso: " + nome);
System.out.println("║ Docente: " + docente);
System.out.println("║ Iscritti: " + studentiIscritti.size() + "/" + maxStudenti);
System.out.println("╠══════════════════════════════════════╣");
for (String studente : getStudentiOrdinatiPerMedia()) {
List<Integer> voti = votiStudenti.get(studente);
double media = calcolaMedia(studente);
System.out.printf("║ %-20s Media: %.2f%n", studente, media);
System.out.println("║ Voti: " + voti);
}
System.out.println("╚══════════════════════════════════════╝");
}
// Getters
public String getNome() { return nome; }
public Set<String> getStudentiIscritti() {
return Collections.unmodifiableSet(studentiIscritti);
}
}
package scuola;
import java.util.*;
public class GestioneCorsi {
private Map<String, Corso> corsi;
private Map<String, Set<String>> iscrizioniStudente;
public GestioneCorsi() {
this.corsi = new HashMap<>();
this.iscrizioniStudente = new HashMap<>();
}
public void aggiungiCorso(Corso corso) {
corsi.put(corso.getNome(), corso);
}
public boolean iscriviStudente(String studente, String nomeCorso) {
Corso corso = corsi.get(nomeCorso);
if (corso == null) {
System.out.println("Corso non trovato: " + nomeCorso);
return false;
}
if (corso.iscrivi(studente)) {
iscrizioniStudente
.computeIfAbsent(studente, k -> new HashSet<>())
.add(nomeCorso);
return true;
}
return false;
}
public Set<String> getCorsiStudente(String studente) {
return iscrizioniStudente.getOrDefault(studente, Collections.emptySet());
}
public void stampaStatistiche() {
System.out.println("\n=== STATISTICHE GLOBALI ===");
System.out.println("Totale corsi: " + corsi.size());
int totaleIscrizioni = iscrizioniStudente.values()
.stream()
.mapToInt(Set::size)
.sum();
System.out.println("Totale iscrizioni: " + totaleIscrizioni);
// Studente con più corsi
String piuAttivo = iscrizioniStudente.entrySet()
.stream()
.max(Comparator.comparingInt(e -> e.getValue().size()))
.map(Map.Entry::getKey)
.orElse("Nessuno");
System.out.println("Studente più attivo: " + piuAttivo);
}
public static void main(String[] args) {
GestioneCorsi gestione = new GestioneCorsi();
// Crea corsi
gestione.aggiungiCorso(new Corso("Programmazione", "Prof. Bianchi", 30));
gestione.aggiungiCorso(new Corso("Database", "Prof. Rossi", 25));
gestione.aggiungiCorso(new Corso("Reti", "Prof. Verdi", 20));
// Iscrivi studenti
gestione.iscriviStudente("Mario", "Programmazione");
gestione.iscriviStudente("Mario", "Database");
gestione.iscriviStudente("Laura", "Programmazione");
gestione.iscriviStudente("Laura", "Reti");
gestione.iscriviStudente("Giuseppe", "Database");
// Registra voti
Corso prog = gestione.corsi.get("Programmazione");
prog.registraVoto("Mario", 28);
prog.registraVoto("Mario", 30);
prog.registraVoto("Laura", 27);
Corso db = gestione.corsi.get("Database");
db.registraVoto("Mario", 25);
db.registraVoto("Giuseppe", 30);
// Stampa riepilogo
prog.stampaRiepilogo();
db.stampaRiepilogo();
// Statistiche
gestione.stampaStatistiche();
System.out.println("\nCorsi di Mario: " + gestione.getCorsiStudente("Mario"));
}
}
결론
컬렉션 프레임워크는 모든 Java 개발자에게 필수적입니다. 올바른 컬렉션을 선택하는 것은 요구 사항에 따라 다릅니다.
기억해야 할 핵심 사항
- 배열목록: 빠른 색인 액세스, 목록의 기본값
- 연결 목록: 빠른 오버헤드 삽입/제거
- 해시세트: 최대 속도의 독창성
- 트리세트: 주문의 독특함
- 해시맵: 빠른 키-값 조회
- 트리맵: 키 정렬
- 우선순위 대기열: 우선순위에 따른 추출
- 어레이데크: 효율적인 스택/큐
에서 다음 기사 우리는 직면하게 될 것이다 관리 오류와 예외: try-catch, throw, 예외 선택 및 선택 취소.







