JAVA in ACTION Jacopo Torrini Dipartimento di Ingegneria dell'Informazione Laboratorio di Tecnologie del Software [email protected] Installazione Java ● ● Su Windows, dal sito Oracle installare l'ultima versione della JDK (7) Su ubuntu aggiungere i repo webupd8team sudo add-apt-repository ppa:webupd8team/java sudo apt-get install oracle-jdk7-installer oppure installare il .run per linux dal sito Oracle Hello World ● Creare un file HelloWorldApp.java class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); } } Compilare ed eseguire ● Da riga di comando: javac HelloWorldApp.java java HelloWorldApp Package ● Permette di definire un namespace per un set di classi tra loro correlate ● ● ● Permette di organizzare meglio il codice tramite una struttura gerarchica di cartelle Permette di avere classi differenti con lo stesso nome dentro package diversi. Risolve soprattutto conflitti di nome su librerie differenti. Permette di definire un accesso limitato a metodi o attributi di una classe alle sole classi dello stesso package Struttura dei package ● ● ● Il package deve contenere uno o più classi o interfacce, ossia non può essere vuoto. Le classi o interfacce che sono in un package devono avere i file sorgenti nella stessa struttura di directory corrispondente al nome del package. Il nome del package viene costruito a partire dal path nel file system del package root (o default) utilizzando come separatore il “.” Esempio di package ● ● Considerando come root package la cartella src la classe MyClass appartiene al package com.mycompany.myproject I .class generati dal compilatore hanno una struttura del tutto equivalente a quella dei sorgenti Nomi delle classi e import ● ● ● ● Come convenzione, per avere nomi di package univoci, si utilizza il dominio della propria azienda/organizzazione in ordine inverso completato con nomi specifici dell'applicazione ( com.mycompany.myproject) Per riferirsi ad una classe deve essere usato il suo nome completo, ossia il nome del package in cui risiede la classe più il nome semplice della classe definito nel .java (com.mycompany.myproject.MyClass) Per abbreviare la scrittura del nome della classe è possibile utilizzare la keyword import: import com.mycompany.myproject.MyClass In questo modo è sufficiente usare MyClass nel codice. In caso di conflitti di nome nello stesso file, una delle due classi deve essere obbligatoriamente usata col nome completo Class files ● ● ● ● ● Quando si compila un programma java vengono generati tanti file .class quante sono le classi java del programma, incluse le classi multiple definite in un unico file java, le nested class e le inner class, anonime e non. Nel caso di classi java semplici, anche se multiple per file, il nome del .class è pari al nome della classe Nel caso di nested o inner class il nome è pari al nome della classe seguito dal simbolo $ seguito dal nome della classe nested o inner Nel caso di inner class anonime vale lo stesso discorso delle classi inner semplici, con la variante che il nome della inner class anonima viene generato dal compilatore (un numero progressivo) I .class sono creati all'interno di cartelle che duplicano la struttura delle cartelle dei file sorgenti Hello World con package ● ● ● ● ● Creare la cartella hello nella cartella root Nella cartella hello creare il file HelloWorldApp.java come l'esempio precedente Aggiungere all'inizio del file lo statement package hello; Compilare il file con javac HelloWorldApp.java Eseguire l'applicazione dalla cartella root con java hello.HelloWorldApp Esecuzione di un programma ● ● Un programma java è un'insieme di file .class all'interno di una struttura di cartelle È sufficiente avere una classe con un metodo public static void main(String[]args) NOTA: Possono esserci più classi con un metodo main ● ● ● Una classe viene caricata dalla virtual machine solo quando viene utilizzata in un altra classe (lazy load) Per trovare una classe la VM utilizza il nome del file .class associato alla classe stessa. Il path del file viene generato tramite il nome del package associato alla classe. Se il file viene trovato viene caricato dalla VM, altrimenti viene sollevata un eccezione. Classpath ● ● ● Finora abbiamo supposto l'esistenza di una sola cartella root. In realtà in java è possibile creare applicazioni i cui file .class stanno su differenti strutture di cartelle (e pure in file compressi). I nomi dei package sono costruiti rispettivamente a partire dalla cartella root di ogni struttura. Ogni cartella root di queste strutture costituisce un componente del classpath di esecuzione di un programma java. Esempio di classpath Jar ● ● ● ● Un insieme di file .class con la propria struttura di cartelle può essere impacchettato all'interno di un file .jar (che altro non è che uno zip). Un jar può essere utilizzato come componente del classpath In questo caso la cartella root è la root dello zip e la virtual machine è in grado di caricare i .class direttamente dal file compresso. Normalmente le librerie java sono semplici file .jar Esecuzione con classpath java -cp /home/user/src1/;src2/ hello.HelloWorldApp java -cp lib.jar;src1/ hello.HellWorldApp API ● ● Application Programming Interface La API fornisce le funzionalità principali del linguaggio Java. Offre un vasto set di classi pronte all'uso per diversi scopi, dagli oggetti di base fino alle classi di networking o security, per la generazione di XML e per l'accesso a database. L'API standard è molto ampia. Object – metodo equals public boolean equals( Object obj ) ● ● ● Esegue un test di uguaglianza logico, basato sul valore. Già definito in Object in cui riporta true solo se l'istanza passata è la stessa di quella su cui si invoca il metodo (obj == this) Inutile ridefinirlo nei seguenti casi: ● Ogni istanza della classe è univoca di per sé (Thread) ● Non mi interessa eseguire un confronto logico (JButton) ● ● ● Una superclasse lo ha già ridefinito e vale anche per la sottoclasse (AbstractSet, AbstractList, AbstractMap) NOTA: è sempre meglio evitare di ridefinirlo in più di una sottoclasse (vedere esempio prossime slide) Quindi si ridefinisce quando per la classe si applica il concetto di logical equality, che vale di solito per value class, come Integer, String, Date. Proprietà che deve rispettare: ● Riflessiva: x.equals(x) is true ● Symmetric: x.equals(y)==y.equals(x) ● Transitiva: x.equals(y), y.equals(z) => x.equals(z) ● Consistenza: x.equals(y) riporta consistentemente true o false se lo stato dell'oggetto non cambia ● x.equals(null) riporta sempre false Esempio con equals public final class PhoneNumber { private final short areaCode; private final short exchange; private final short extension; public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof PhoneNumber)) return false; //questo include o==null PhoneNumber pn = (PhoneNumber)o; return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode; } } Esempio equals con ereditarietà public class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point p = (Point)o; return p.x == x && p.y == y; } } public class ColorPoint extends Point { private Color color; public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; } //Broken - violates symmetry! public boolean equals(Object o) { if (!(o instanceof ColorPoint)) return false; ColorPoint cp = (ColorPoint)o; return super.equals(o) && cp.color == color; } } Object – metodo hashCode public int hashCode() ● Riporta un intero che rappresenta l'hash code dell'oggetto ● Definito in Object e riporta un valore associato all'istanza dell'oggetto ● ● Deve essere ridefinito in tutte le classi che ridefiniscono equals in modo da funzionare bene nelle collezioni basate su hash code (Set, Map) Valgono le seguenti proprietà: ● ● ● ● Deve riportare un valore consistente se chiamato più volte sulla stessa istanza. Se lo stato dell'oggetto non cambia deve riportare sempre lo stesso valore. Non è necessario che riporti il medesimo valore su esecuzioni differenti del programma. Se due istanze sono uguali per valore, ossia x.equals(y) riporta true, allora il metodo hashCode deve riportare lo stesso intero se invocato sulle due istanze. Non è necessario che hashCode riporti valori differenti per due istanze che non sono equals, ma va tenuto conto che produrre valori differenti per istanze non equals può migliorare la performance delle hash table. Esempi di hashCode public int hashCode() { int result = 17; result = 37*result + areaCode; result = 37*result + exchange; result = 37*result + extension; return result; } //valido ma da non usare!! public int hashCode() { return 42; } Altre considerazioni ● ● Un altro metodo interessante di Object è public String toString(). Deve essere usato solo a scopi di debug e deve dare una rappresentazione testuale dell'oggetto I metodi equals e hasCode possono essere generati automaticamente. Le IDE per lo sviluppo java di solito hanno questa funzionalità Collections ● ● A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data. Typically, they represent data items that form a natural group, such as a poker hand (a collection of cards), a mail folder (a collection of letters), or a telephone directory (a mapping of names to phone numbers). A collections framework is a unified architecture for representing and manipulating collections. All collections frameworks contain the following: ● ● ● Interfaces: These are abstract data types that represent collections. Interfaces allow collections to be manipulated independently of the details of their representation. In object-oriented languages, interfaces generally form a hierarchy. Implementations: These are the concrete implementations of the collection interfaces. In essence, they are reusable data structures. Algorithms: These are the methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. The algorithms are said to be polymorphic: that is, the same method can be used on many different implementations of the appropriate collection interface. In essence, algorithms are reusable functionality. Java collections - interfaces Collection interface The Collection interface contains methods that perform basic operations, such as ● ● ● int size() ● boolean isEmpty() ● boolean contains(Object element) ● boolean add(E element) ● boolean remove(Object element) ● Iterator<E> iterator() It also contains methods that operate on entire collections, such as ● boolean containsAll(Collection<?> c) ● boolean addAll(Collection<? extends E> c) ● boolean removeAll(Collection<?> c) ● boolean retainAll(Collection<?> c) ● void clear(). Additional methods for array operations such as ● Object[] toArray(). Traversing collections For-each construct for (Object o : collection) System.out.println(o); ● Iterator: An Iterator is an object that enables you to traverse through a collection and to remove elements from the collection selectively, if desired. You get an Iterator for a collection by calling its iterator method. The following is the Iterator interface. public interface Iterator<E> { boolean hasNext(); E next(); void remove(); //optional } ● for (Iterator<String> it = c.iterator(); it.hasNext(); ){ String s = it.next(); System.out.println(s); } Collection algorithms ● The polymorphic algorithms are pieces of reusable functionality provided by the Java platform. All of them come from the Collections class, and all take the form of static methods whose first argument is the collection on which the operation is to be performed. The great majority of the algorithms provided by the Java platform operate on List instances, but a few of them operate on arbitrary Collection instances. ● Sorting ● Shuffling ● Routine Data Manipulation (reverse, fill, copy, swap, addAll) ● Searching ● Composition (frequency, disjoint) ● Finding Extreme Values (min, max) Set ● ● A Set is a Collection that cannot contain duplicate elements. It models the mathematical set abstraction. The Set interface contains only methods inherited from Collection and adds the restriction that duplicate elements are prohibited. Set also adds a stronger contract on the behavior of the equals and hashCode operations, allowing Set instances to be compared meaningfully even if their implementation types differ. Two Set instances are equal if they contain the same elements. The Java platform contains three general-purpose Set implementations: HashSet, TreeSet, and LinkedHashSet Set<String> noDups = new HashSet<String>(); Collection<Integer> other = new TreeSet<Integer>(); List ● A List is an ordered Collection (sometimes called a sequence). Lists may contain duplicate elements. In addition to the operations inherited from Collection, the List interface includes operations for the following: ● ● ● ● ● Positional access — manipulates elements based on their numerical position in the list. This includes methods such as get, set, add, addAll, and remove. Search — searches for a specified object in the list and returns its numerical position. Search methods include indexOf and lastIndexOf. Iteration — extends Iterator semantics to take advantage of the list's sequential nature. The listIterator methods provide this behavior. Range-view — The sublist method performs arbitrary range operations on the list. The Java platform contains two general-purpose List implementations. ArrayList, which is usually the better-performing implementation, and LinkedList which offers better performance under certain circumstances. List<Integer> list = new ArrayList<Integer>(); Map ● ● A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value. It models the mathematical function abstraction. The Map interface includes methods for basic operations (such as put, get, remove, containsKey, containsValue, size, and empty), bulk operations (such as putAll and clear), and collection views (such as keySet, entrySet, and values). The Java platform contains three general-purpose Map implementations: HashMap, TreeMap, and LinkedHashMap Map<String, Integer> m = new HashMap<String, Integer>(); m.put(“William”,1955); m.put(“Steven”, 1955); m.put(“Linus”, 1969); IDE ● ● ● Sviluppare da riga di comando non è il modo corretto. Una IDE (Integrated Development Environment) è necessaria per avere una serie di funzionalità indispensabili per lo sviluppo del software. Esistono varie IDE open source o gratuite: Eclipse, Net beans, IntelliJ IDEA community edition... Eclipse ● Fornisce una piattaforma aperta per tool di sviluppo di applicazioni ● Gira su un vasto range di sistemi operativi ● Language-neutral ● HTML, Java, C, JSP, EJB, XML ● Facilita l’integrazione di tool Eclipse – gestione codice ● ● ● Esplorazione dei packages e delle classi con struttura ad albero Ricerca veloce della dichiarazione di un metodo, una classe di una variabile Informazioni istantanee sugli elementi del codice ● tooltip sull’elemento ● documentazione dell’elemento ● Ricerca di elementi in più files ● Caller graph dei metodi Eclipse – scrittura codice ● ● Evidenziazione immediata errori di sintassi Completamento automatico di classi, variabili, metodi ● Import automatici ● Code formatter ● Code templates ● Scrittura automatica di main, override di metodi, setter e getter, costruttori, delegate methods, equals e hashCode ecc... Eclipse - rifattorizzazione ● ● ● Conoscere in anticipo l’impatto di una modifica sul codice Possibilità di modificare un elemento mantenendo la semantica di tutto il codice Possibilità di decidere quali cambiamenti effettuare ● Preview dei cambiamenti ● Undo e Redo del refactoring ● Esempi: rename, change method signature, pull up, pull down... Eclipse – debug e test ● Step in, out, over... ● Breakpoints ● Conditional breakpoints ● Variables ● Watches ● Stack trace ● Integrazione con JUnit Eclipse - installazione ● Scaricare Eclipse IDE for Java EE Developers dalla pagina web: http://www.eclipse.org/downloads/ ● Scompattare in una qualsiasi cartella ● Aprire tramite il file eseguibile ● ● Selezionare una cartella come workspace (anche quello di default) Sotto Windows – Preferences – Java - Installed JREs verificare che sia selezionata una JDK (non una JRE). In caso contrario aggiungerne una e selezionarla dal file system Eclipse – creazione progetto java ● Dal menu File selezionare New – Java Project ● Seguire il wizard fino in fondo e premere Fine. ● ● ● Cliccare col destro sulla cartella src nel Package Explorer e selezionare New – Class Specificare un nome di package e un nome di classe e premere Fine Ogni volta che un file viene salvato, viene anche compilato automaticamente Eclipse – esecuzione ● ● ● Definire il metodo main in una classe java Cliccare col destro sul nome del file java nel Package Explorer Lanciare il comando Run as – Java application Eclipse – UI ● Configurazione dell'interfaccia ● Perspectives ● Package explorer ● Outline ● Javadoc ● Breakpoints Eclipse – multiprogetto e librerie ● ● Creazione di un altro progetto Impostazione del primo progetto nel classpath del secondo ● ● ● Click col destro sul progetto – properties – java build path - Projects Utilizzo di classi del primo progetto nel secondo progetto Aggiunta di librerie esterne ● Click col destro sul progetto - Properties – java build path - Libraries