Slide sesta lezione al linguaggio Java 8 in preparazione alla certificazione OCA 1Z0-808.
Argomenti:
Librerie indispensabili e famose (StringTokenizer, StringBuilder, DateTime API)
Collections Framework & Stream API, Gestione input e Output
Lezione del 11-01-2018 tenuta da Valerio Radice presso Nextre Engeneering
https://www.nextre.it/corso/corso-java-oca/
3. Di cosa si parlerà ?
Librerie indispensabili e famose (StringTokenizer, StringBuilder, DateTime API)
Collections Framework & Stream API, Gestione input e Output
4. StringTokenizer
Appartenente al pacchetto java.util
Permette di rompere una stringa in sotto-stringhe dette token
Manipola solo stringhe, non fa differenza tra numeri, caratteri o altro
Presente da molte versioni (JDK 1.0)
Come separatore di default usa lo spazio
È possibile usare come delimitatore una serie di caratteri
5. StringTokenizer
Costruttori
StringTokenizer(String str) = splitta la stringa col delimitatore di default
StringTokenizer(String str, String delim) = splitta la stringa col delimitatore
scelto
StringTokenizer(String str, String delim, boolean returnDelim) = come il
precedente ma include tra i risultati il delimitatore
Metodi
countTokens() = ritorna il numero di tokens ottenuti
hasMoreTokens() / hasMoreElements() = ritorna un booleano che indica la
presenza del prossimo elemento
nextToken() / nextElement() = ritorna il token come stringa ("token") o come
oggetto ("element")
6. StringTokenizer
public class StringTokenizerSample {
public static void main(String[] args) {
StringTokenizer st = new StringTokenizer("I topi non avevano nipoti");
System.out.println("tokens count: " + st.countTokens());
while (st.hasMoreElements()) {
String token = st.nextElement().toString();
System.out.println("token = " + token);
}
// Dividere una data con lo "/"
st = new StringTokenizer("11/01/2018", "/");
while (st.hasMoreElements()) {
String token = st.nextToken();
System.out.println("token = " + token);
}
}
}
8. StringBuilder & StringBuffer
Dato che le stringhe sono immutabili, per costruire una stringa mutabile si
utilizza StringBuilder (non sincronizzato) o StringBuffer (sincronizzato).
Diversi metodi per manipolare le stringhe:
Append
Insert
Delete
Reverse
Replacing
….
Modificano sempre la stessa locazione di memoria
10. Due modi di rappresentare il tempo
Tempo macchina: è rappresentato da un numero intero che si incrementa
sempre. Il suo punto di partenza è l’1 Gennaio 1970 (valore assoluto). È il modo
in cui la macchina rappresenta il tempo, in millisecondi, a partire da tale data.
Tempo umano: è come noi umani rappresentiamo il passare del tempo. Ore,
minuti, secondi per un orario e le date giorni, settimane, mesi, anni e secoli.
Ogni cultura ha il suo calendario (es: gregoriano). Nel mondo lo stesso tempo
assoluto è soggetto al fuso orario.
11. Date, Time & DateTime
Java mette a disposizione diverse classi per gestire le date e il tempo.
Il tempo è una misura assoluta, uguale per tutti, ma cambia la rappresentazione.
A seconda del luogo (Locale) in cui ci troviamo abbiamo una differente
rappresentazione.
La classe Date è la meno recente, e soffre di diverse imprecisioni, per
compatibilità è rimasta anche se molti metodi sono deprecati.
A sostituirla ci ha pensato prima la classe Calendar e GregorianCalendar per
gestire date e orari, infine la più recente classe di Java8 con DateTime API
(Joda-Time, immutabile).
12. java.util.Date
La classe java.util.Date rappresenta un intervallo di tempo che va dal
01/01/1970 all’istante di creazione dell’oggetto Date
Ci sono due costruttori dell’oggetto Date:
Date() = Inizializza all’istante attuale
Date(long date) = Inizializza all’istante di tempo passato come parametro
13. Metodi non deprecati
boolean after(Date when) //controlla se la data è prima un’altra
specifica data
boolean before(Date when) //controlla se la data è dopo un’altra
specifica data
long getTime() //ritorna un numero in millisecondi a partire dal
01/01/1970 00:00:00 GMT che rappresenta la specifica data
void setTime(long time) //setta la data tramite il parametro passato
String toString() //converte l’oggetto Date in una String con una
specifica formattazione (dd hh:mm:ss zzz yyyy) (Thu May 21 10:07:28
CEST 2016)
boolean equals // confronta due date per vedere se sono uguali
int hashCode() // ritorna l’hash code dell’oggetto
Object clone() // ritorna una copia dell’oggetto
int compareTo(Date anotherDate) //confronta due date per
l’ordinazione
14. Java.util.Calendar e
java.util.GregorianCalendar
La classe Calendar è una classe astratta che definisce tutti i metodi per la gestione e
manipolazione delle date.
È una classe astratta, quindi per utilizzarla bisogna far riferimento ad una sua
implementazione.
Per avere un’stanza della classe Calendar possiamo utilizzare il metodo statico getInstance() o
utilizzare la classe java.utl.GregorianCalendar che è un’implementazione della classe
Calendar
Calendar data = Calendar.getInstance();
Calendar data2 = new GregorianCalendar();
15. LocalDate (Package java.time (Java 8))
È una classe immutabile (come la classe String),
non si può istanziare. Per usarla bisogna richiedere
un'istanza
Un’istanza di LocalDate rappresenta un valore (es:
22/05/2001) e non offre alcuna informazione
temporale. La data impostata nell’istanza avrà
inizio in momenti diversi nella timeline in base alla
posizione sulla terra della macchina su cui viene
fatta l’istanza.
LocalDate d1 = LocalDate.now();
16. Caratteristiche del package java.time
(Java 8)
Metodi chiari, definiti, comuni e standardizzati
Gli oggetti temporali (che rappresentano
un’istante o arco temporale) sono tutti
immutabili
È fluente ossia può concatenare le chiamate
una dopo l’altra (chaining)
È estendibile ossia riconosce altri tipi di
calendari
LocalDate today = LocalDate.now();
LocalDate ultimoGiorno = today.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(today.until(ultimoGiorno).getDays());
18. Metodi
LocalDate data = LocalDate.now();
data.isLeapYear(); // ritorna true se l’anno è bisestile, false altrimenti
data.lengthOfMonth(); // ritorna il numero di giorni del mese
data.getDayOfWeek(); // ritorna il giorno della settimana (1Lunedì-7Domenica)
data.withYear(2016); // ritorna un’istanza della classe LocalDate con la data
impostata nell’istanza data ma con anno indicato nel metodo withYear(…)
data.plusMonths(2); // ritorna un’istanza della classe LocalDate con la data
impostata nell’istanza data ma con mese calcolato partendo dal mese di data più il
numero indicato nel metodo plusMonths(…)
data.minusDays(5); // ritorna un’istanza della classe LocalDate con la data
impostata nell’istanza data ma con giorno calcolato partendo dal mese di data
meno il numero indicato nel metodo minusDays(…)
19. Java.time.LocalTime
Classe immutabile usata per la gestione delle ore del giorno. Un’istanza (timeA)
della classe LocalTime rappresenta un orario, senza alcuna data associata e senza
fuso orario.
Alcuni metodi:
timeA.getHour(); // ritorna l’ora impostata nell’istanza della classe
timeA.getMinute(); // ritorna i minuti impostati nell’istanza della classe
timeA.withSecond(10); // ritorna un’istanza di LocalTime che ha come orario quello
impostato nell’istanza di partenza (timeA) alla quale vengono aggiunti i secondi
indicati nel metodo withSecond(…)
timeA.plusMinutes(3); // ritorna un’istanza di LocalTime che ha come orario quello
impostato nell’istanza di partenza (timeA) alla quale vengono aggiunti i minuti indicati
nel metodo plusMinutes(…)
timeA.minusHours(3); // ritorna un’istanza di LocalTime che ha come orario quello
impostato nell’istanza di partenza (timeA) alla quale vengono sottratte le ore indicate
nel metodo minusHours(…)
timeA.plusHours(5); // ritorna un’istanza di LocalTime che ha come orario quello
impostato nell’istanza di partenza (timeA)
20. Instant, Duration e Period
Instant rappresenta un determinato istante nel tempo in nanosecondi a partire dal
01/01/1970
Duration rappresenta un intervallo di tempo rappresentato in ore, minuti, secondi,
millisecondi e nanosecondi ecc… max intervallo rappresentabile un giorno (inteso come
24). Non ha informazioni sul giorno.
Period rappresenta un periodo di tempo (più ampio di Duration) calcolato tra due date
sotto forma di anni, mesi, giorni. Non ha informazioni di tempo.
ATTENZIONE a quando si formatta perché non avendo informazioni si possono sollevare
eccezioni
21. DayOfWeek e Month
Rappresentano due enumerazioni per rappresentare rispettivamente i giorni della
settimana e i mesi dell'anni.
Ritornando i valori dell'enumerazione ( getValue() ) si ottengono i numeri da 1 a 7
per i giorni della settimana a partire da Lunedì; e da 1 a 12 per i mesi a partire
da Gennaio.
Implementano lo standard ISO-8601
22. Geolocalizzazione
ZoneId e ZoneOffset sono le due principali classi per localizzare un'ora nel
mondo.
Permettono di ottenere informazioni sul fuso orario e sulla zona della
macchina in uso.
Permettono di impostare tali parametri
Consentono l'interpretazione di date e orari con diversi fusi orari e
convenzioni
23. DateFormatter e SimpleDateFormatter
Una data è un oggetto che rappresenta un dato momento nel tempo, ma
quando deve essere mostrata si può avere la necessità di contestualizzarla
secondo la lingua, la zona e il fuso orario.
Esistono diversi formattatori, a partire dal tipo di data usato si ha la
possibilità di convertire una data da una classe a un'altra e usare il
formattatore migliore.
I formattatori usano un parser per decidere il formato di stampa
dell'informazione della data.
24. DateFormatter e SimpleDateFormatter
parse() è il metodo che ci permette di rileggere una stringa e ottenere un
oggetto Date, LocalDate, LocalDateTime, Time ecc…
Dato un formato (pattern) in ingresso, posso leggere una stringa e convertirla
in un oggetto della classe sul quale eseguire delle operazioni.
Per capire come impostare il pattern si consiglia di leggere la documentazione
della classe di cui si vuole ottenere l'oggetto.
DateTimeFormatter.ISO_LOCAL_DATE = "yyyy-MM-dd"
25. Java.time.temporal
Insieme di classi per gestire unità temporali, eseguire operazioni per il calcolo
di date e orari, ottenere informazioni sugli oggetti data e ora che si
utilizzano. Tra le più diffuse abbiamo:
Enumerazione ChronoUnit = definisce unità di misura del tempo
TemporalAdjusters = ottengo / calcolo informazioni su date e tempi
TemporalQueries = ottengo informazioni sugli oggetti che uso (es: la
precisione della data)
26. Esempio
LocalDate ddn = LocalDate.parse("1985-07-07");
LocalDateTime ddns = LocalDateTime.parse("1985-07-07 00:00:00",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//LocalDate ddn = LocalDate.of(1985,07,07); //altro modo
Long days = ddn.until(LocalDate.now(),ChronoUnit.DAYS);
System.out.println("Da quando sono nato (" + ddn + ") sono passati:");
System.out.println("Giorni: " + days);
System.out.println("Anni: " + Period.between(ddn,adesso).get(ChronoUnit.YEARS) );
System.out.println("Secondi di vita: " +
Duration.between(ddns,LocalDateTime.now()).get(ChronoUnit.SECONDS) );
System.out.println("Battiti del cuore di vita: " +
Duration.between(ddns,LocalDateTime.now()).get(ChronoUnit.SECONDS)*60L );
27. Esempio
LocalDate adesso = LocalDate.now();
System.out.println(adesso);
System.out.println(adesso.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
31. Collection Framework
Rappresenta un insieme di classi e interfacce, contenute in java.util, per mettere
a disposizione delle strutture dati dinamiche per organizzare, ordinare gli
oggetti.
Una collezione rappresenta un insieme di differenti oggetti, ma dello stesso tipo,
organizzati in un'unica entità.
Il Collection Framework contiene:
liste
set
mappe
32.
33. Dichiarazione
Usiamo un reference di Collection per puntare a tutte le implementazioni che
appartengono allo stesso albero gerarchico per il polimorfismo per metodi.
Questa pratica che sfrutta il polimorfismo per dati, permette, nel caso in cui ne
avessimo necessità, di cambiare il tipo dell’oggetto: per esempio con una LinkedList
l’unica riga da cambiare sarebbe solo la dichiarazione.
Collection<String> collection = new ArrayList<>();
34. Metodi comuni
int size() ritorna il numero degli elementi contenuti nella collezione
boolean add(E element) aggiunge un elemento alla collezione e restituisce
true o false a seconda del fatto che l’operazione sia andata a buon fine o
meno
boolean remove(Object element) rimuove un elemento dalla collezione e
restituisce true o false a seconda del fatto che l’operazione sia andata buon
fine o meno
boolean isEmpty() restituisce true o false a seconda del fatto che la collezione
contenga elementi o meno
void clear() elimina tutti gli elementi dalla collezione
35. Metodi comuni
boolean contains(Object element) restituisce true o false a seconda del fatto
che l’elemento specificato in input sia contenuto nella collezione o meno
Iterator<E> iterator() restituisce un’implementazione di un’interfaccia
Iterator che serve per iterare sugli elementi della collezione
boolean containsAll(Collection<?> c) restituisce true o false a seconda del
fatto che gli elementi della collezione specificata in input siano tutti o meno
contenuti nella collezione su cui viene chiamato il metodo. Questo
indipendentemente dall’ordine degli oggetti nelle collezioni
36. Metodi comuni
boolean addAll(Collection<? extends E> c) aggiunge tutti gli elementi della
collezione specificata in input alla collezione su cui è stato chiamato il
metodo, e restituisce true o false a seconda del fatto che l’operazione sia
andata a buon fine o meno
boolean removeAll(Collection<?> c) rimuove tutti gli elementi della collezione
specificate in input, della collezione su cui è stato chiamato il metodo, e
restituisce true o false a seconda del fatto che l’operazione sia andata a buon
fine o meno
boolean retainAll(Collection<?> c) per la collezione su cui è stato chiamato il
metodo conserva solamente gli elementi della confezione specificata in input,
rimuovendo gli altri, e restituisce true o false a seconda del fatto che
l’operazione sia andata a buon fine o meno
37. Metodi comuni
L’interfaccia Collection definisce anche metodi per gli array
Object[] toArray() restituisce un array di Object a partire da una collezione
<T> T[] toArray(T[] a) restituisce un array di oggetti di tipo parametro T a
partire da una collezione
38. Metodi comuni
Infine, questa interfaccia espone i metodi stream() e parallelStream(). Questi
restituiscono oggetti di tipo Stream che consentono di eseguire cicli in maniera
sequenziale o parallela alla collezione.
Iterare sulle collezioni
usando i cicli foreach
usando iteratori
usando i metodi di default forEach() definito nell’interfaccia Collection e
sfruttando le cosiddette operazioni di aggregazione con la nuova libreria
Stream API
39. Il ciclo foreach
L’interfaccia Collection estende l’interfaccia Iterable, e tutto quello che
estende Iterable può essere iterato tramite un ciclo foreach. Es:
for (String email : newsletters) {
System.out.println(email);
}
40. Iterator
Sono oggetti che astraggono dei cursori per eseguire cicli sugli elementi di una
collezione. Essi possono spostarsi elemento per elemento partendo dal primo e
arrivando all’ultimo, e in generale non possono cambiare direzione e tornare
indietro.
L’interfaccia Iterator viene usata sfruttando il metodo iterator() di Collection.
Iterator<String> Iterator = newsletters.iterator();
41. Iterator
L’interfaccia Iterator definisce tre metodi:
hasNext() restituisce true se l’iteratore non si trova sull’ultimo elemento
next() fa avanzare di un passo l’iteratore
remove() rimuove l’elemento corrente
forEachRemaining() prende in input un oggetto di tipo Consumer. Questo è un metodo
di default, quindi ha già un’implementazione, ma questo ci interessa relativamente.
Esso esegue l’operazione specificata di tutti gli elementi su cui bisogna ancora
eseguire il ciclo, fino a quando sono finiti oppure se scatta un’eccezione
42. Iterator
Il metodo forEach() prende in input un oggetto di tipo Consumer.
Questo significa che qualsiasi collezione potrà iterare direttamente sui suoi
elementi semplicemente chiamando questo metodo, e passandogli in input
un’espressione lambda per fare operazioni sugli stessi elementi
newsletters.forEach( e -> System.out.println(e));
43. List
L’interfaccia List rappresenta una collezione ordinata e indicizzata di elementi
in cui sono ammessi duplicati, eredita tutti i metodi che vengono ereditati
dall’interfaccia Collection.
La sequenza di come gli elementi sono aggiunti in una lista ne definisce l'ordine.
44. List
L’interfaccia List permette di:
Avere accesso posizionale (get, set, remove)
Effettuare ricerche (indexOf, lastIndexOf)
Iterare gli elementi (listIterator)
Ottenere sotto-liste (sublist)
45. List: metodi principali
get(): prende in input un indici intero e restituisce l’oggetto corrispondente a
quell’indice
add(): prende in input l’elemento da aggiungere e l’indice della posizione dove
deve essere inserito, spostando tutti gli altri elementi avanti di uno
set(): prende in input l’elemento da aggiungere e l’indice della posizione dove
deve essere inserito, sovrascrivendo l’elemento in quella posizione se presente
listIterator(): permette di ottenere un oggetto di tipo ListIterator , che permette
di iterare in entrambe le direzioni
46. List: implementazioni
ArrayList
È la collezione più utilizzata, sostituisce la classe Vector perché hanno le stesse
funzionalità ma ArrayList non è sincronizzata, di conseguenza è più performante
ArrayList <String> list = new ArrayList<>();
LinkedList
È una lista concatenata, ogni elemento mantiene un reference verso l’elemento
successivo e l’elemento precedente. Si utilizza quando si devono aggiungere
spesso elementi all’inizio della lista o quando si vogliono eliminare elementi
all’interno della lista durante le iterazioni
LinkedList <String> linked = new LinkedList<>();
47. Set
L’interfaccia Set rappresenta una collezione non ordinata di elementi in cui non
sono ammessi duplicati
Metodi principali
add(): aggiunta di un elemento
iterator(): restituisce un iteratore sugli elementi di questo insieme
48. SortedSet
L’interfaccia SortedSet rappresenta una collezione ordinata di elementi in cui
non sono ammessi duplicati
Metodi principali
Comparator(): restituisce il comparatore utilizzato per ordinare gli elementi
di questo insieme o null se si utilizza l’ordinamento naturale
spliterator(): può essere utilizzato per dividere l'elemento dato in set multipli
in modo che possiamo eseguire alcune operazioni/calcoli su ciascun set in
thread diversi indipendentemente.
49. Set: implementazioni
Un’implementazione di Set è HashSet, mentre un’implementazione di SortedSet
è TreeSet, entrambe non ammettono elementi duplicati. Un’altra
implementazione importante è LinkedHashSet
HashSet
È la più utilizzata perché garantisce prestazioni migliori
TreeSet
Viene utilizzata quando bisogna iterare in maniera ordinata sugli elementi della
collezione
LinkedHashSet
È una collezione simile all’HashSet. Rispetto all’HashSet mantiene anche l’ordine
degli elementi compatibile con il loro ordine di inserimento (come nelle liste)
50. Coda
Una coda è una collezione proge6ata per mantenere oggetti che devono
essere processati
Gli elementi in una coda sono mantenuti secondo un certo ordine:
FIFO (es. coda alla posta)
LIFO (es. stack)
La testa (o head) della coda è l’elemento che verrà rimosso da una chiamata
al metodo remove() o poll().
51. Interfacce Queue e Deque
Fanno parte di java.util
estendono l'interfaccia Collection ed è possibile accedere all'elemento di testa o
di coda nella lista o entrambe
un esempio classico che implementa queste interfacce è la classe LinkedList
Metodi comuni
offer() metodo per l'inserimento in testa alla coda (add())
poll() metodo per l'eliminazione elemento in testa alla coda (remove())
peek() metodo per l'estrazione elemento in testa alla coda (element())
add(), remove(), element() possono sollevare eccezioni.
52. Queue
Oltre alle operazioni ereditate dall'interfaccia Collection, l'interfaccia Queue
permette di:
Accedere e/o rimuovere un elemento in testa alla coda
Aggiungere un elemento in testa o in coda
Inserire un elemento alla fine (tail) della coda (ordinamento FIFO) o in testa
(ordinamento LIFO)
53. Queue, Deque, BlockingDeque,
NavigationSet e NavigationMap
Una Deque, è una coda a cui è possibile accedere da entrambi gli estremi (sia in
inserimento che in rimozione).
Per la gestione di sistemi multithread Java offre l’utilizzo dell’interfaccia
BlockingDeque, che estende Deque e che effettua "l’attesa di spazio disponibile",
nel caso di inserimento in coda piena, e l’attesa di un elemento inserito nel caso
di coda vuota.
I Set e Map navigabili (NavigationSet e NavigationMap) definiscono il
comportamento di un set e una mappa rispettivamente, permettendo delle
funzioni di navigazione e attraversamento dei nodi in maniera ordinata. La
versione concorrente (ConcurrentNavigableMap) verrà utilizzata nel caso di
possibile accesso concorrente.
54. LIFO: "Last In, First Out"
ultimo elemento inserito è il primo rimosso
La testa della coda è il primo elemento ad essere inserito
Questo modello viene utilizzato nella struttura dati STACK - un esempio può essere una
pila di libri che utilizzano i metodi:
push() per aggiungere un elemento in cima alla lista
pop() per rimuovere un elemento dalla cima della lista
peek() ritorna un elemento ma non lo rimuove
i metodi pop e peek lanciano una eccezione di tipo java.util.EmptyStackException se
la pila su cui sono invocati è vuota;
55. FIFO: "First In, First Out"
primo elemento inserito è il primo rimosso
Una LinkedList può essere sia FIFO che LIFO in quanto implementa anche i metodi
addFirt(), getFirst() e removeFirst() e i corrispettivi:
offerFirst() e offerLast() aggiungono al primo o al'ultimo elemento
pollFirst() e pollLast() ritornano primo/ultimo elemento
removeFirstOccurrency() e removeLastOccurency() ritornano un boolean
peekFirst() e peekLast() estraggono il primo o l'ultimo elemento
56. Esempio
PriorityQueue puo contenere dati secondo il loro ordine naturale(se implementa
l'interfaccia Comparable) o secondo un Comparator passato a PriorityQueue
Queue<Integer> nums = new LinkedList <Integer>();
Queue queueB = new PriorityQueue();
nums.offer(1);
nums.offer(2);
nums.offer(3);
nums.offer(4);
coda testa
output : 4 3 2 1
sout(nums.peek()) --> 1
sout(nums.poll()) --> 4 3 2
sout(nums.remove()) --> 4 3
sout(nums.poll()) --> 4
sout(nums.remove()) --> empty
sout(nums.remove()) --> error
sout(nums.poll()) --> null
sout(nums.peek()) --> null
sout(nums.element()) -->error
57. Queue VS Deque
QUEUE DEQUE
Aggiunta e rimozione solo dalla testa
della coda
Aggiunta e rimozione sia dalla testa che
dalla coda
FIFO LIFO e FIFO
60. java.io & java.nio
java mette a disposizione diverse classi che consentono di :
creare file e directory, cercare file e directory, rinominare file e directory,
scrivere all' interno di un file, leggere il contenuto in un file
le classi principali per la gestione dei file si trovano nel package java.io e da
java 1.8 il package java.nio 2.0 (new input output)
la classe java.io contiene una collezione di classi che supportano gli algoritmi
per leggere e scrivere.
61. java.io: lettura e scrittura attraverso
stream
STREAM : canale di comunicazione tra un programma (Java) e una sorgente
(destinazione) da cui importare (verso cui esportare) dati! Aprire uno stream
significa aprire un canale di comunicazione per fare passare queste informazioni.
Tutti gli stream sono automaticamente aperti quando creati, ogni stream si
dovrebbe chiudere esplicitamente chiamando il metodo close(), il garbage
collector non puo chiudere lo stream se questo è ancora aperto e di conseguenza
non potrà deallocare la memoria.
Conviene chiudere gli stream ogni volta che è possibile per migliorare le
prestazioni dell'applicazione.
62. java.io: lettura e scrittura attraverso
stream
Dalla versione 7 di java si può utilizzare il costrutto "TRY WITH RESOURCES" che chiude
automaticamente lo stream.
try(FileReader fileReader = new FileReader("test.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader)){
String riga= bufferedReader.readLine();
while (riga != null){
System.out.println(riga);
riga = bufferedReader.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
63. Tipi di stream
sono divise in due gerarchie separate, in base al tipo di informazioni che devono
trasportare:
byte: servono a leggere/scrivere sequenze di byte, informazioni non testuali
(ad es file binari come immagini o suoni). Sono implementati dalle superclassi
astratte InputStream e OutputStream. Leggono 8bit alla volta.
Caratteri: servono a leggere/scrivere file con una codifica Unicode, dividono
il file in blocchi da 16bit, compatibile col tipo char di Java. Implementati
dalle interfacce Reader e Writer.
68. java.io.File
La classe File è una rappresentazione di un file o una directory.
Permette di creare, eliminare o controllarne l'esistenza un file o una directory
Il costruttore della classe File riceve in ingresso una variabile di tipo String
che contiene al suo interno il path del file. Istanziando un oggetto File non si
può creare fisicamente il file o la directory su disco fisso. Per poterlo creare
fare devo chiamare il metodo createNewFile() per la creazione di un file,
mkdir() per creare una cartella.
69. java.io.File
Costruttori della classe File:
File(String pathname)
File(String dir,String subpath)
File(File dir,String subpath)
Metodi principali della classe File per manipolare file o/e directory, ma non per
leggere/scrivere. Per leggere/scrivere su/da un file bisogna prima associare uno
stream al file
exists() :return true se il file o la directory esiste, false altrimenti
createNewFile() :crea un file su fisco nel path specificato
delete() : elimina il file o la directory dal disco
isFile() : return true se è un file , false altrimenti
isDir() : return true se è una directory, false altrimenti
mkDir() crea una directory sul disco nel path specificato
70. SCRITTURA FILE - OUTPUT
java.io.FileWriter - consente di scrivere in un file di testo un carattere per volta
java.io.BufferedWriter - consente di scrivere i caratteri nel file in blocchi,
memorizzati in un buffer temporaneo, i caratteri vengono quindi letti dal buffer e
scritti su file. Questa classe a differenza di FileWriter è sincronizzata (threadsafe).
Con meno accessi al disco è più performante.
java.io.PrintWriter - è simile alla classe bufferedWriter ma consente anche di
scrivere il testo formattato
71. 4 ways to write a file
FileWriter: FileWriter is the simplest way to write a file in java, it provides
overloaded write method to write int, byte array and String to the File. You can
also write part of the String or byte array using FileWriter. FileWriter writes
directly into Files and should be used only when number of writes are less.
BufferedWriter: BufferedWriter is almost similar to FileWriter but it uses internal
buffer to write data into File. So if the number of write operations are more, the
actual IO operations are less and performance is better. You should use
BufferedWriter when number of write operations are more.
FileOutputStream: FileWriter and BufferedWriter are meant to write text to the
file but when you need raw stream data to be written into file, you should use
FileOutputStream to write file in java.
Files: Java 7 introduced Files utility class and we can write a file using it’s write
function, internally it’s using OutputStream to write byte array into file.
72. LETTURA FILE - INPUT
java.io.FileReader - permette di leggere i caratteri del file di testo leggendoli
1 alla volta
java.io.BufferedReader - consente di leggere presenti nel file in blocchi,
memorizzati in un buffer temporaneo, quando i caratteri vengono richiesti,
vengono letti dal buffer. Questa classe è più performante rispetto alla classe
FileWriter perché è sincronizzata (threadsafe).
73. JAVA NIO 2.0
Java New Input Output
Rispetto a java.io e NIO, c'è stato bisogno di implementare alcune funzioni per
manipolare i file, come ad esempio il metodo per copiare un file o una directory.
Contiene molti metodi booleani per avere un feedback veloce evitando di
lanciare un'eccezione in caso di fallimento.
Approfondimento:
https://docs.oracle.com/javase/8/docs/technotes/guides/io/index.html
74. JAVA NIO 2.0
Con java 7 sono stati introdotti i channel, (che non sostituiranno gli stream ma
facilitano l'utilizzo delle risorse), rispetto agli stream sono capaci di gestire più
situazioni in comtemporanea, come nel caso si voglia lavorare con file protetti o
si vogliano utilizzare stream non bloccati (ovvero che non si bloccano se
aspettano un input).
Sono stati introdotti nuovi package java.nio.file, java.nio.file.spi,
java.nio.file.attribute.
Le novità piu importanti sono date grazie all' introduzione della classe Files e
dell' interfaccia Path che forniscono metodi più semplici per lavorare con i file.
Nuovi metodi utili:
toPath() nella classe File per ottenere un oggetto Path
toFile() nella classe Path per ottenere un oggetto File
75. Interfaccia PATH
Per poterla utilizzare è necessario utilizzare l'oggetto FileSystem o più
semplicemente la classe Paths che offre metodi statici per tornare un Path.
Esempi:
Path path1 = FileSystem.getDefault().getPath("/root/afile.txt");
Path path2 = Paths.get("C:Program FilesEJE");
Un' istanza di Path rappresenta un path ("percorso") nel file system , un path
può puntare sia ad un file che una directory, un path può essere assoluto o
relativo:
- assoluto parte dalla root del sistema e punta al file o alla cartella voluta
- relativo contiene il percorso del file o di una cartella relativo ad un altro
percorso.
76. Interfaccia PATH
Per poter utilizzare java.nio.file.Path bisogna ottenere un'istanza di Path.
L'istanza si crea chiamando il metodo Paths.get("percorso"). Esempio:
Path path2 = Paths.get("C:datamyfile.txt");
Esempio Path relativo:
Path directory = Paths.get("d:data", "projects");
Path file = Paths.get("d:data", "projectsa-projectmyfile.txt");
il primo (directory) punta alla directory "projects" situata nel base path assoluto,
mentre il secondo (file) punta al file (myFile.txt) contenuto nel percorso
specificato come secondo parametro a partire dalla directory assoluta.
77. Interfaccia PATH
subPath() restituisce il numero di elementi che compongono il path
escludendo il nodo radice(C:, in unix/Linux è /)
getRoot() serve ad identificare il nodo radice
getParent() restituisce la cartella in cui è contenuto il file rappresentato
dall'oggetto Path.
toUri() restituisce il path in formato URI (Unicode Resource Identifier)
relativize() restituisce il percorso che serve per andare dal path su cui si
chiama il metodo al path che viene passato come parametro
metodo per leggere file di piccole dimensioni sono readAllBytes() per leggere
file binari e readAllLines() per leggere file di testo. per i metodi di scrittura è
write() che prendono in ingresso array di bytes o di stringhe a seconda del
tipo di dato che si vuole trattare.
78. Classe Files
Classe di utilità per manipolare File/Directory
contiene solo metodi statici
a livello di file system sia file che directory sono comunque files e non viene
fatta distinzione.
79. Classe Files: copy()
copy(Path source, Path target, CopyOption... options);
Copia di un file da un path iniziale a uno finale
path source è il path iniziale
path target il path di destinazione
copyOption è un varargs di tipo CopyOption (Enum)
le enumerazioni di Copyoption :
REPLACE_EXISTING (il file esistente verrà sovrascritto),
COPY_ATTRIBUTES (copia anche gli attributi del file)
NOFOLLOW_LINK (se il file è link simbolico non viene seguito, per copiare solo
il link, non copia il file).
80. Classe Files: copy()
E' possibile copiare una directory ma i file contenuti in essa non saranno
copiati. esiste anche un altro overload del metodo copy che consente di
interagire con InputStream e OutputStream per leggere e scrivere i file.
Si possono anche fare delle copie ricorsive utilizzando l'interfaccia FileVisitor.
Non è possibile copiare al volo una cartella e tutto il contenuto con il metodo
copy. Bisogna sviluppare un metodo ricorsivo apposito.
81. Classe Files
createDirectory / createDirectories -> permette di creare una directory e una
directory in odo ricorsivo.
createFile -> consente di generare un nuovo file vuoto, terminerà con
insuccesso in caso il file esista già.
createLink -> tenta di creare un link a un file esistente.
createTempDirectory / createTempFile -> creare file temporanei.
delete -> per eliminare un file o la directory specificata (in caso di tentata
eliminazione cartella non vuota, viene generata un' eccezione
(DirectoryNotEmptyException).
size -> restituisce le dimensioni del file specificato in termini di byte.
82. Classe Files
delete -> consente di cancellare un file ma deleteIfExist non solleva eccezioni
nel caso la cancellazione fallisca. Potrebbe lanciare un eccezione IOexception
se si hanno problemi con i permessi di cancellazione del file,
noSuchFileException se si prova ad eliminare un file che non esiste o
DirectoryNotEmptyException se si prova ad eliminare una directory non vuota.
deleteIfExists -> elimina un file o directory se esiste. La differenza con il
metodo precedente è che questo ritorna un valore booleano per specificare se
l'operazione ha avuto successo o meno.
exists /notExists -> verifica se il file (o directory) specificato esiste o meno e
solleva un eccezione SecurityException in caso il file non sia accessibile.
isReadable/isWritable/isExecutable -> servono rispettivamente per capire i
permessi di leggibilità, scrittura ed esecuzione.
83. Classe Files
getFileStore -> restituisce un oggetto di tipo FileStore che rappresenta il
luogo dove il file è localizzato.
getLastModifiedTime, getOwner, getPosixFilePermissions -> consente di
ottenere il timestamp dell' ultima modifica avvenuta, il possessore del file e i
permessi di questi metodi c'è anche il set di tutti(per impostarli)
isDirectory, isExecutable, isHidden, isReadable, isRegularFile, isSymbolicLink,
isWritable -> questi metodi permettono di capire se un determinato file (o
directory) possiede o meno la proprietà specificata dal metodo.
move -> permette di spostare o rinominare il file (o directory) specificato nel
path di destinazione.
isSameFile -> permette di comparare i file/directory specificati dai rispettivi
path. Restituisce un valore true se si tratta degli stessi file.
84. Classe Files
readAllBytes, readAllLines -> Questi metodi si occupano di caricare in
memoria l'intero file memorizzandolo, rispettivamente, in un array di byte e
in una lista di stringhe. Da notare che questi metodi possono lanciare un
OutOfMemoryError.
write -> permette di scrivere dei byte o delle linee di testo (a seconda
dell'overloading del metodo utilizzato) nel file specificato. In questo caso è
possibile specificare dei parametri di scrittura del file, come per esempio
APPEND, CREATE_NEW, e così via.
probeContentType -> ispeziona il contenuto del file per identificarne il tipo,
che viene restituito secondo lo standard MIME (Multipurpose Internet Mail
Extension). Questo metodo utilizza le implementazioni della classe astratta
java.nio.file.spi.FileTypeDetector (sempre introdotta con Java SE7) fornita dal
service provider per ispezionare il file per determinarne il tipo.
85. Classe Files
walkFileTree -> si tratta di un metodo molto potente che permette di
effettuare la navigazione di una parte (albero) del file system a partire dal
nodo (file) dato.
readAllBytes() -> permette di leggere file binari di piccole dimensioni
readAllLines() -> permette di leggere file letterali di piccole dimensioni.
writeAllBytes() -> permette di scrivere file binari di piccole dimensioni da
array di bytes.
writeAllLines() -> permette di scrivere file letterali di piccole dimensioni a
partire da array di stringhe.
86. Classe Files
La classe Files definisce diversi metodi per scrivere e leggere file, molti di questi prendono in input come parametro opzionale uno
o più elementi dell' enumerazione StandardOpenOption:
WRITE - apre il file con accesso in scrittura
READ - apre il file con accesso in lettura
APPEND - aggiunge nuovi dati alla fine del file, solitamente con write o create
CREATE - crea un file se non esiste
CREATE_NEW - crea un file e se già esiste solleva un eccezione.
DELETE_ON_CLOSE - cancella il file quando lo stream viene chiuso
DSYNC - mantiene il contenuto del file sincronizzato con il dispositivo di storage sottostante
SPARSE - suggerisce che il file appena creato sia in formato "sparso"
SYNC - mantiene il file (sia di contenuti che metadati ) sincronizzato con il dispositivo di storage sottostante
TRUNCATE_EXISTING - tronca il file a zero byte, questa opzione viene utilizzata in congiunzione a WRITE
87. Classe Files: example
public static void main(String[] args) {
Path path = null;
try {
path = Files.createTempDirectory("mypdf");
} catch (IOException e1) {
System.out.print("Woops. We have a problem "+e1);
}
if (path != null) {
System.out.println("Create new temp directory:""+path+""");
URI uri = URI.create("http://www.itisff.it/dip_eln/reti.pdf");
try (InputStream in = uri.toURL().openStream()) {
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.out.print("Woops. We have a problem "+e);
}
}
}
88. Classe Files: example
public static void main(String[] args){
final String THIS_SOURCE_FILE =
"C:/prj/java_se_7/src/resource/excel_worksheet.xlsx";
Path path = FileSystems.getDefault().getPath(THIS_SOURCE_FILE);
try {
System.out.println("Last modified time:"
+Files.getLastModifiedTime(path));
System.out.println("Owner:"+Files.getOwner(path));
System.out.println("Size:"+Files.size(path));
System.out.println("Type:"+Files.probeContentType(path));
} catch (IOException e) {
System.out.println("Wooops we have a problem:"+e.getMessage());
}
}