コレクションフレームワーク
Il コレクションフレームワーク Java は統一されたアーキテクチャです オブジェクトのグループを表現および操作します。インターフェースを提供し、 データを効率的に管理するための実装とアルゴリズム。
何を学ぶか
- コレクションインターフェイスの階層
- リスト: ArrayList と LinkedList
- セット: HashSet、TreeSet、LinkedHashSet
- マップ: ハッシュマップ、ツリーマップ、および LinkedHashMap
- キューとデキュー
- コレクションのアルゴリズムとユーティリティ
コレクション階層
メインインターフェース
| インタフェース | 説明 | 実装 |
|---|---|---|
| コレクション | ルートインターフェース | - |
| リスト | 重複のある順序付けされたシーケンス | 配列リスト、リンクリスト |
| セット | ユニークな要素 | ハッシュセット、ツリーセット |
| Queue | FIFOキュー | LinkedList、PriorityQueue |
| 地図 | キーと値のペア | ハッシュマップ、ツリーマップ |
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 の比較
| 手術 | 配列リスト | リンクリスト |
|---|---|---|
| 取得(インデックス) | O(1) - 高速 | O(n) - 遅い |
| 追加(要素) | O(1) 減価償却 | ○(1) |
| add(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(log n) | 並べ替えられた要素 |
| リンクされたハッシュセット | 挿入 | ○(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 クラスのアルゴリズム
クラス 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 開発者にとって不可欠です。 適切なコレクションの選択は、要件によって異なります。
覚えておくべき重要なポイント
- 配列リスト: 高速インデックスアクセス、リストのデフォルト
- リンクされたリスト: オーバーヘッドの素早い挿入/取り外し
- ハッシュセット: 最高のスピードを備えた独自性
- ツリーセット: 注文による独自性
- ハッシュマップ: 高速なキーと値のルックアップ
- ツリーマップ: キーがソートされました
- 優先キュー: 優先度による抽出
- 配列デック: 効率的なスタック/キュー
Nel 次の記事 私たちは直面します 管理 エラーと例外の: トライキャッチ、スロー、例外 チェックが入ったものとチェックが外されたもの。







