Sunteți pe pagina 1din 19

Disciplina: Metode avansate de programare

Cadru didactic: Ralf Fabian


Specializarea: Informatică, anul II.

Interfeţe și colecții în Java

O clase conţine atribute şi metode. Metodele se compun dintr-un capul (prototip) şi un corp.
Capul de metodă reprezintă interfaţa unui obiect cu lumea exterioară.
Interfeţele permit, ca şi clasele, definirea unor noi tipuri de date. O interfaţă Java defineşte
un set de metode dar nu specifică nici o implementare pentru ele. O clasă care implementează o
interfaţă trebuie obligatoriu să specifice implementări pentru toate metodele interfeţei,
supunându-se aşadar unui anumit comportament.
Pentru că este posibil ca o clasă să implementeze mai mult de o interfaţă, interfeţele
reprezintă o alternativă pentru moştenirea multiplă, care nu este permisă în Java.

Definirea unei interfeţe


O interfaţă este declarată într-un mod asemănător cu o clasă, doar că în locul cuvântului
class se foloseşte cuvântul cheie interface.

[public] interface NumeInterfata


[extends SuperInterfata1, SuperInterfata2...]{
// Corpul interfetei:
// Date membre – constante
// Metode membre – funcţii abstracte, metode fără implementare
}

O interfaţă poate avea un singur modificator şi anume public. O interfaţă publică este
accesibilă tuturor claselor, indiferent de pachetul din care fac parte, implicit nivelul de acces fiind
doar la nivelul pachetului din care face parte interfaţa.
Spre deosebire de moştenirea claselor, cuvântul cheie extends permite specificarea a mai
multor interfeţe, separate prin virgulă, care pot fi combinate într-o unitate logică mai mare.

Date membre – constante


Modificatorii pentru datele membre ale unei interfeţe, se limitează la un anumit set: public,
static, final. Prin urmare variabilele membre din interfeţe pot avea doar valori constante.
Modificatorii public, static final sunt impliciţi, adică, declararea lor explicită nu este necesară, dar
uşurează înţelegerea codului.

interface Test{
int PI = 3.14;
// Echivalent cu:
public static final int PI = 3.14;

int MAX; // Incorect, lipseste initializarea

private int x = 1; // Incorect, modificator nepermis


}

1
Metode membre – fără implementare
Modificatorii pentru metode se limitează la: public. Acesta este implicit, prezenţa lui nefiind
necesară, dar uşurează înţelegerea codului.

interface Test{
void functie();
// Echivalent cu:
public void functie();
}

Implementarea unei interfeţe


Implementarea uneia sau mai multor interfeţe de către o clasă se face prin intermediul
cuvântului cheie implements:

class NumeClasa implements NumeInterfata


sau
class NumeClasa implements Interfata1, Interfata2, ...
sau
class NumeClasa1 extends NumeClasa2 implements Interfata1, Interfata2, ...

O clasă poate implementa oricâte interfeţe sau nici una. In cazul în care implementează o
anumită interfaţă, atunci trebuie obligatoriu să specifice cod pentru toate metodele interfeţei
respective.
Interfeţele şi superclasele nu se exclud reciproc. O clasă nouă poate fi derivată dintr-o
superclasă şi poate implementa una sau mai multe interfeţe.
Modificarea unei interfeţe (adăugarea unor metode noi sau schimbarea signaturii metodelor
existente) implică modificarea tuturor claselor care implementează acea interfaţă.
O clasă poate avea şi alte metode şi variabile membre în afară de cele definite în interfaţă.
Implementarea unei interfeţe poate să fie şi o clasă abstractă.

interface Ceas {
public String citesteTimpul();
}

class CeasCuLimbi implements Ceas {


public String citesteTimpul() {
String str ="CeasCuLimbi";
java.util.Date data = new java.util.Date();

for (int i=1; i <= data.getHours(); i++)


str=str+" "+i;
return str;
}
}

class CeasElectronic implements Ceas{


public String citesteTimpul(){
java.util.Date data = new java.util.Date();
return new String("CeasElectronic
"+data.getHours()+":"+data.getMinutes()+":"+data.getSeconds());
}

public static void main(String args[]){


System.out.println(new CeasCuLimbi().citesteTimpul());
System.out.println(new CeasElectronic().citesteTimpul());
}
}

2
Output-ul va fi:
CeasCuLimbi 1 2 3 4 5 6 7 8
CeasElectronic 8:28:11

Interfaţa ca tip de date


O interfaţă nu este o clasă ca urmare nu se pot instanţa obiecte de tip interfaţă, dar orice
referinţă de tip interfaţă poate primi ca valoare o referinţă la un obiect al unei clase ce
implementează interfaţa respectivă. Din acest motiv, interfeţele pot fi privite ca tipuri de date şi se
poate spune că un obiect are tipul X, unde X este o interfaţă, dacă acesta este o instanţă a unei clase
ce implementează interfaţa X. Pentru exemplul de mai sus avem:

Ceas c;
c = new Ceas(); //Eroare, nu se pot instanta obiecte de tip Ceas
c=new CeasCuLimbi(); //Corect, pt. ca CeasCuLimbi implementeaza Ceas

Iniţializarea câmpurilor din interfeţe


Câmpurilor din interfeţe sunt automat statice şi finale dar ele pot fi iniţializate cu expresii
neconstante, ca de exemplu:

import java.util.*;

public interface RandVals {


Random rand = new Random();
int randomInt = rand.nextInt(10);
long randomLong = rand.nextLong() * 10;
float randomFloat = rand.nextLong() * 10;
double randomDouble = rand.nextDouble() * 10;
}

Întrucât câmpurile sunt statice ele vor fi iniţializate la prima încărcare a clasei, ceea ce are
loc la primul acces a unuia dintre câmpuri.

Gruparea de constate
Interfeţele sunt instrumente utile pentru a realiza o grupare de constante, dată fiind natura
statică şi finală a câmpurilor acestora.

public interface Lunile {


int
IANUARIE = 1, FEBRUARIE = 2, MARTIE = 3,
APRILIE = 4, MAI = 5, IUNIE = 6, IULIE = 7,
AUGUST = 8, SEPTEMBRIE = 9, OCTOMBRIE = 10,
NOIEMBRIE = 11, DECEMBRIE = 12;
}

Valorile acestor constant pot fi accesate din exterior prin expresii de forma
Lunile.NOIEMBRIE, evident că rezultatul va fi un int. Pentru obţinerea unei siguranţe de tip
(type safety) mai ridicate se poate scrie o clasă de forma:

3
public final class Luni {
private String nume;
private Luni(String nl) { nume = nl; }
public String toString() { return nume; }
public static final Luni IAN = new Luni("Ianuarie"),
FEB = new Luni("Februarie"),
MAR = new Luni("Martie"),
APR = new Luni("Aprilie"),
MAI = new Luni("Mai"),
IUN = new Luni("Iunie"),
IUL = new Luni("Iulie"),
AUG = new Luni("August"),
SEP = new Luni("Septembrie"),
OCT = new Luni("Octombrie"),
NOI = new Luni("Noiembrie"),
DEC = new Luni("Decembrie");
public static final Luni[] lunile = {
IAN, FEB, MAR, APR, MAI, IUN,
IUL, AUG, SEP, OCT, NOI, DEC
};
public static final Luni numar(int ord) {
return lunile[ord - 1];
}
public static void main(String[] args) {
Luni m = Luni.IAN;
System.out.println(m);
m = Luni.numar(12);
System.out.println(m);
System.out.println(m == Luni.DEC);
System.out.println(m.equals(Luni.DEC));
System.out.println(Luni.lunile[3]);
}
}
Output-ul este
Ianuarie
Decembrie
true
true
Aprilie

Luni este o clasă finală cu constructor privat, aşa că nu pot exista derivări sau instanţe ale
acestei clase. Singurele instanţe, sunt cele finale şi statice create în interiorul clasei: IAN, FEB, etc.
Ele sunt folosite şi în vectorul lunile ceea ce permite o iteraţie pe un vectori de obiecte de tip
Luni. Metoda numar() permite selectarea unei luni pe baza unui număr dat.
În funcţia principală variabila m este un obiect de tip Luni, spre deosebire de exemplul de
mai sus, unde era de tip int, permiţând astfel o asociere cu orice valoare întreagă.

Interfeţe vs. clase Abstracte


Variabile Constructor Metode
Clase Fără restricţii Nu poate fi instanţiată cu Fără restricţii.
abstracte operatorul new.
Constructorii se apelează
de subclase prin înlănţuire
de constructori.
Interfeţe Toate variabilele trebuie Nu există constructori. O Toate metodele trebuie
să fie declarate interfaţă nu poate fi să fie public abstract.
public static final instanţiată cu operatorul
new.

4
Interfeţe pentru compararea obiectelor
O soluţie simplă de sortare a unui vector este folosirea metodei sort din clasa
java.util.Arrays.

int v[]={3, 1, 4, 2};


java.util.Arrays.sort(v);
// Sorteaza vectorul v
// Acesta va deveni {1, 2, 3, 4}

În cazul în care elementele din vector sunt de tip primitiv nu există nici o problemă în a
determina ordinea firească a elementelor.
Pentru a vedea ce se întâmplă atunci când vectorul conţine referinţe la obiecte să
considerăm următorul exemplu, în care urmărim să sortăm un vector format din instanţe ale
clasei Persoana.

class Persoana {
int cod ;
String nume ;
public Persoana ( int cod , String nume ) {
this.cod = cod;
this.nume = nume ;
}
public String toString () {
return cod + " \t " + nume ;
}

public static void main ( String args []) {


Persoana p[] = new Persoana [4];
p[0] = new Persoana (6, " Ionescu ");
p[1] = new Persoana (1, " Vasilescu ");
p[2] = new Persoana (3, " Georgescu ");
p[3] = new Persoana (4, " Popescu ");
java . util . Arrays . sort (p);
//nu se poate aplica pt. ca p este un vector de obiecte
}
}

Interfaţa Comparable
Interfaţa Comparable impune o ordine totală asupra obiectelor unei clase ce o
implementează. Această ordine este specificată prin intermediul metodei compareTo. Definiţia
interfeţei este:

public interface Comparable {


int compareTo(Object o);
}

Aşadar, o clasă ale cărei instanţe trebuie să fie comparabil între ele va implementa metoda
compareTo care poate returna:
 valoare strict negativă: dacă obiectul curent (this) este mai mic decât obiectul primit ca
argument;
 zero: dacă obiectul curent este egal cu obiectul primit ca argument;
 valoare strict pozitivă: dacă obiectul curent este mai mare decât obiectul primit ca
argument.

5
Pentru o ordonare a persoanelor după codul lor intern se procedează astfel:

class Persoana implements Comparable {


int cod ;
String nume ;

public Persoana ( int cod , String nume ) {


this.cod = cod;
this.nume = nume ;
}
public String toString () {
return cod + " \t " + nume ;
}
public boolean equals ( Object o) {
if (!( o instanceof Persoana ))
return false ;
Persoana p = ( Persoana ) o;
return (cod == p.cod) && ( nume . equals (p. nume ));
}
public int compareTo ( Object o) {
if (o== null ){
System.out.println("Lipseste un obiect!");
System.exit(-1);
}
if (!( o instanceof Persoana )){
System.out.println("Nu pot compara!");
System.exit(-2);
}
Persoana p = ( Persoana ) o;
return (cod - p.cod );
}
}

Interfaţa Comparator
Pentru cazul în care se doreşte o sortare a elementelor unui vector, ce conţine referinţe,
după alt criteriu decât ordinea naturală a elementelor, există o soluţie oferită tot de metoda sort
din clasa java.util.Arrays, dar în varianta în care, pe lângă vectorul ce trebuie sortat, se
transmite un argument de tip Comparator care să specifice modalitatea de comparare a
elementelor.
Interfaţa java.util.Comparator conţine metoda compare, care impune o ordine
totală asupra elementelor unei colecţii. Aceasta returnează un întreg cu aceeaşi semnificaţie ca
la metoda compareTo a interfeţei Comparable şi are următoarea definiţie:

public int compare(Object o1, Object o2);

Pentru o ordonare după numele persoanelor se poate proceda astfel:

import java.util.*;
class Sortare {
public static void main ( String args []) {
Persoana p[] = new Persoana [4];
p[0] = new Persoana (3, " Ionescu ");
p[1] = new Persoana (1, " Vasilescu ");
p[2] = new Persoana (2, " Georgescu ");
p[3] = new Persoana (4, " Popescu ");
Arrays.sort (p, new Comparator () {
public int compare ( Object o1 , Object o2) {
Persoana p1 = ( Persoana )o1;
Persoana p2 = ( Persoana )o2;

6
return (p1.nume.compareTo(p2.nume ));
}//implementare cu clasa interna anonima
});
System.out.println(" Persoanele ordonate dupa nume :");
for (int i=0; i<p.length ; i++)
System.out.println (p[i]);
}
}

Compararea a două şiruri de caractere se face tot cu metoda compareTo, clasa String
implementând interfaţa Comparable.

Colecţii de obiecte
O colecţie este un obiect care grupează mai multe elemente într-o singură unitate. Prin
intermediul colecţiilor vom avea acces la diferite tipuri de date cum ar fi vectori, liste înlănţuite,
stive, mulţimi matematice, tabele de dispersie, etc.
Colecţiile sunt folosite atât pentru memorarea şi manipularea datelor, cât şi pentru
transmiterea unor informaţii de la o metodă la alta.
Tipul de date al elementelor dintr-o colecţie este Object, ceea ce înseamnă că mulţimile
reprezentate sunt eterogene, putând include obiecte de orice tip.
Colecţiile sunt tratate într-o manieră unitară, fiind organizate într-o arhitectură foarte eficientă şi
flexibilă ce cuprinde:
 Interfeţe: tipuri abstracte de date ce descriu colecţiile şi permit utilizarea lor
independent de detaliile implementărilor.
 Implementări: implementări concrete ale interfeţelor ce descriu colecţii. Aceste clase
reprezintă tipuri de date reutilizabile.
 Algoritmi: metode care efectuează diverse operaţii utile cum ar fi căutarea sau sortarea,
definite pentru obiecte ce implementează interfeţele ce descriu colecţii. Aceşti algoritmi
se numesc şi polimorfici deoarece pot fi folosiţi pe implementări diferite ale unei
colecţii, reprezentând elementul de funcţionalitate reutilizabilă.

Cele mai importante avantaje ale colecţiilor sunt:


 Reducerea efortului de programare: prin punerea la dispoziţia programatorului a unui set
de tipuri de date şi algoritmi ce modelează structuri şi operaţii des folosite în aplicaţii.
 Creşterea vitezei şi calităţii programului: implementările efective ale colecţiilor sunt de
înaltă performanţă şi folosesc algoritmi cu timp de lucru optim.
 La scrierea unei aplicaţii se poate concentra eforturile asupra problemei în sine şi nu
asupra modului de reprezentare şi manipulare a informaţiilor.

Interfeţe de colecţii
Interfeţele reprezintă nucleul mecanismului de lucru cu colecţii, scopul lor fiind de a
permite utilizarea structurilor de date independent de modul lor de implementare. Structura
ierarhică a principalelor interfeţe de colecţii este dată de figura următoare:

7
Collection
Interfaţa Collection modelează o colecţie la nivelul cel mai general, descriind un grup
de obiecte numite şi elementele sale. Unele implementări ale acestei interfeţe permit existenţa
elementelor duplicate, alte implementări nu. Unele au elementele ordonate, altele nu. Platforma
Java nu oferă nici o implementare directă a acestei interfeţe, ci există doar implementări ale
unor subinterfeţe mai concrete, cum ar fi Set sau List.

public interface Collection {


// Metode cu caracter general
int size();
boolean isEmpty();
void clear();
Iterator iterator();
// Operatii la nivel de element
boolean contains(Object element);
boolean add(Object element);
boolean remove(Object element);
// Operatii la nivel de multime
boolean containsAll(Collection c);
boolean addAll(Collection c);
boolean removeAll(Collection c);
boolean retainAll(Collection c);
// Metode de conversie in vector
Object[] toArray();
Object[] toArray(Object a[]);
}

Până la JDK 1.5 Collection a fost proiectat pentru a lucra cu java.lang.Object,


întrucât clasa Object fiind clasa de bază a tuturor claselor din Java, oricărei clase se poate
aplicat un upcast spre Object.
La extragerea unui element dintr-o colecție este în sarcina programatorului să aplice un
downcast asupra obiectului de tip Object pentru al converti din nou în tipul clasei sale
originale.
Începând cu JDK 1.5 s-a introdus genericitatea pentru a elimina această problemă cu
upcast/downcast. Prin genericitate putem stabili tipul obiectelor dintr-o colecție prin sintaxa
<tip>, de exemplu: List<String> lst = new ArrayList<String>();

Obs: Clasa Collections conține metode statice cu algoritmi polimorfici care lucrează cu
colecții (shuffle, sort, copy, fill, revers, rotate etc.).

8
Parcurgerea colecțiilor cu Iterable și Interator
Interfața Iterable definește un mecanism de iterare/traversare a tuturor elementelor dintr-o
colecție printr-un obiect Iterator. Interfața Iterable definește o singură metodă abstractă:

Iterator<T> iterator();

care returnează obiectul Iterator asociat care poate fi folosit pentru parcurgerea tuturor
elementelor din colecție.
Interfața Iterator declară următoarele metode abstracte:

boolean hasNext() // returnează true dacă mai sunt elemente


E next() // returnează următorul element
void remove() // șterge ultimul element returnat de iterator

9
Exemplu: Parcurgerea unei colecții.

import java.util.*;

public class ArrayListTest {


public static void main(String[] args) {
List<String> lst = new ArrayList<String>(); // tipul elementelor e
String
lst.add("alpha"); // compilatorul verifică dc. arg. e
String
lst.add("beta");
lst.add("charlie");
Iterator<String> iter = lst.iterator(); // Iterator pt. Strings
while (iter.hasNext()) {
String str = iter.next(); // compilatorul aplică downcat automat
System.out.println(str);
}

lst.add(new Integer(1234)); // ERROR: compilatorul poate detecta


tipul
Integer intObj = lst.get(0); // ERROR: compilatorul poate detecta
tipul
}
}

Parcurgerea colecțiilor cu for-each


O altă variantă de parcurgere a unei colecții este cu folosirea buclei for-each. Această
alternativă ascunde obiectul Iterator, ca urmare nu pot fi eliminate (via Iterator.remove()) sau
înlocuite elemente din colecție.

List<String> lst = new ArrayList<String>();


lst.add("alpha");
lst.add("beta");
lst.add("charlie");
// pentru fiecare element de tip String str din colecția lst
for (String str : lst) { // compilatorul face downcasting-ul necesar
System.out.println(str);
}

Set
Interfaţa Set modelează noţiunea de mulţime în sens matematic. O mulţime nu poate
avea elemente duplicate. Moşteneşte metodele din Collection, fără a avea alte metode
specifice.
Două dintre clasele standard care oferă implementări concrete ale acestei interfeţe sunt
HashSet şi TreeSet.

SortedSet
Interfaţa SortedSet este asemănătoare cu interfaţa Set, diferenţa principală constând
în faptul că elementele dintr-o astfel de colecţie sunt ordonate ascendent.
Pune la dispoziţie operaţii care beneficiază de avantajul ordonării elementelor.
Ordonarea elementelor se face conform ordinii lor naturale, sau conform cu ordinea dată de un
comparator specificat la crearea colecţiei şi este menţinută automat la orice operaţie efectuată
asupra mulţimii. Singura condiţie este ca, pentru orice două obiecte o1, o2 ale colecţiei, apelul
o1.compareT o(o2) (sau comparator.compare(o1, o2), dacă este folosit un
comparator) trebuie să fie valid şi să nu provoace excepţii.
10
Fiind subclasă a interfeţei Set, moşteneşte metodele acesteia, oferind metode
suplimentare ce ţin cont de faptul că mulţimea este sortată.
public interface SortedSet extends Set {
// Subliste
SortedSet subSet(Object fromElement, Object toElement);
SortedSet headSet(Object toElement);
SortedSet tailSet(Object fromElement);
// Capete
Object first();
Object last();
Comparator comparator();
}

Clasa care implementează această interfaţă este TreeSet.

Exemplu. Utilizare de TreeSet şi SortedSet.

import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSetTest


{
private static final String names[] = { "yellow", "green",
"black", "tan", "grey", "white", "orange", "red", "green" };

// create a sorted set with TreeSet, then manipulate it


public SortedSetTest()
{
// create TreeSet
SortedSet< String > tree =
new TreeSet< String >( Arrays.asList( names ) );

System.out.println( "sorted set: " );


printSet( tree ); // output contents of tree

// get headSet based on "orange"


System.out.print( "\nheadSet (\"orange\"): " );
printSet( tree.headSet( "orange" ) );

// get tailSet based upon "orange"


System.out.print( "tailSet (\"orange\"): " );
printSet( tree.tailSet( "orange" ) );

// get first and last elements


System.out.printf( "first: %s\n", tree.first() );
System.out.printf( "last : %s\n", tree.last() );
} // end SortedSetTest constructor

// output set
private void printSet( SortedSet< String > set )
{
for ( String s : set )
System.out.printf( "%s ", s );

System.out.println();
} // end method printSet

public static void main( String args[] )


{
new SortedSetTest();

11
} // end main
} // end class SortedSetTest

List
Interfaţa List descrie liste (secvenţe) de elemente indexate. Listele pot conţine
duplicate şi permit un control precis asupra poziţiei unui element prin intermediul indexului
acelui element. In plus, faţă de metodele definite de interfaţa Collection, avem metode pentru
acces poziţional, căutare şi iterare avansată.

public interface List extends Collection {


// Acces pozitional
Object get(int index);
Object set(int index, Object element);
void add(int index, Object element);
Object remove(int index);
abstract boolean addAll(int index, Collection c);
// Cautare
int indexOf(Object o);
int lastIndexOf(Object o);
// Iterare
ListIterator listIterator();
ListIterator listIterator(int index);
// Extragere sublista
List subList(int from, int to);
}

Clase standard care implementează această interfaţă sunt: ArrayList, LinkedList, Vector.

Exemplu. Utilizarea interfetei Collection.


import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionTest


{
private static final String[] colors =
{ "MAGENTA", "RED", "WHITE", "BLUE", "CYAN" };
private static final String[] removeColors =
{ "RED", "WHITE", "BLUE" };

// create ArrayList, add Colors to it and manipulate it


public CollectionTest()
{
List< String > list = new ArrayList< String >();
List< String > removeList = new ArrayList< String >();

// add elements in colors array to list


for ( String color : colors )
list.add( color );

// add elements in removeColors to removeList


for ( String color : removeColors )
removeList.add( color );

System.out.println( "ArrayList: " );

12
// output list contents
for ( int count = 0; count < list.size(); count++ )
System.out.printf( "%s ", list.get( count ) );

// remove colors contained in removeList


removeColors( list, removeList );

System.out.println( "\n\nArrayList after calling removeColors: " );

// output list contents


for ( String color : list )
System.out.printf( "%s ", color );
} // end CollectionTest constructor

// remove colors specified in collection2 from collection1


private void removeColors(
Collection< String > collection1, Collection< String > collection2 )
{
// get iterator
Iterator< String > iterator = collection1.iterator();

// loop while collection has items


while ( iterator.hasNext() )

if ( collection2.contains( iterator.next() ) )
iterator.remove(); // remove current Color
} // end method removeColors

public static void main( String args[] )


{
new CollectionTest();
} // end main
} // end class CollectionTest

Exemplu. Utilizarea metodei toArray pe liste.

import java.util.LinkedList;
import java.util.Arrays;

public class UsingToArray


{
// constructor creates LinkedList, adds elements and converts to array
public UsingToArray()
{
String colors[] = { "black", "blue", "yellow" };

LinkedList< String > links =


new LinkedList< String >( Arrays.asList( colors ) );

links.addLast( "red" ); // add as last item


links.add( "pink" ); // add to the end
links.add( 3, "green" ); // add at 3rd index
links.addFirst( "cyan" ); // add as first item

// get LinkedList elements as an array


colors = links.toArray( new String[ links.size() ] );

System.out.println( "colors: " );

for ( String color : colors )


System.out.println( color );
} // end UsingToArray constructor

13
public static void main( String args[] )
{
new UsingToArray();
} // end main
} // end class UsingToArray

Exemplu. Utilizarea clasei Vector.

import java.util.Vector;
import java.util.NoSuchElementException;

public class VectorTest


{
private static final String colors[] = { "red", "white", "blue" };

public VectorTest()
{
Vector< String > vector = new Vector< String >();
printVector( vector ); // print vector

// add elements to the vector


for ( String color : colors )
vector.add( color );

printVector( vector ); // print vector

// output the first and last elements


try
{
System.out.printf( "First element: %s\n", vector.firstElement());
System.out.printf( "Last element: %s\n", vector.lastElement() );
} // end try
// catch exception if vector is empty
catch ( NoSuchElementException exception )
{
exception.printStackTrace();
} // end catch

// does vector contain "red"?


if ( vector.contains( "red" ) )
System.out.printf( "\n\"red\" found at index %d\n\n",
vector.indexOf( "red" ) );
else
System.out.println( "\n\"red\" not found\n" );

vector.remove( "red" ); // remove the string "red"


System.out.println( "\"red\" has been removed" );
printVector( vector ); // print vector

// does vector contain "red" after remove operation?


if ( vector.contains( "red" ) )
System.out.printf(
"\"red\" found at index %d\n", vector.indexOf( "red" ) );
else
System.out.println( "\"red\" not found" );

// print the size and capacity of vector


System.out.printf( "\nSize: %d\nCapacity: %d\n", vector.size(),
vector.capacity() );
} // end Vector constructor

private void printVector( Vector< String > vectorToOutput )

14
{
if ( vectorToOutput.isEmpty() )
System.out.print( "vector is empty" ); // vectorToOutput is empty
else // iterate through the elements
{
System.out.print( "vector contains: " );

// output elements
for ( String element : vectorToOutput )
System.out.printf( "%s ", element );
} // end else

System.out.println( "\n" );
} // end method printVector

public static void main( String args[] )


{
new VectorTest(); // create object and call its constructor
} // end main
} // end class VectorTest

Exemplu. Clasa Stack moşteneşte clasa Vector.

import java.util.Stack;
import java.util.EmptyStackException;

public class StackTest


{
public StackTest()
{
Stack< Number > stack = new Stack< Number >();

// create numbers to store in the stack


Long longNumber = 12L;
Integer intNumber = 34567;
Float floatNumber = 1.0F;
Double doubleNumber = 1234.5678;

// use push method


stack.push( longNumber ); // push a long
printStack( stack );
stack.push( intNumber ); // push an int
printStack( stack );
stack.push( floatNumber ); // push a float
printStack( stack );
stack.push( doubleNumber ); // push a double
printStack( stack );

// remove items from stack


try
{
Number removedObject = null;

// pop elements from stack


while ( true )
{
removedObject = stack.pop(); // use pop method
System.out.printf( "%s popped\n", removedObject );
printStack( stack );
} // end while
} // end try
catch ( EmptyStackException emptyStackException )

15
{
emptyStackException.printStackTrace();
} // end catch
} // end StackTest constructor

private void printStack( Stack< Number > stack )


{
if ( stack.isEmpty() )
System.out.print( "stack is empty\n\n" ); // the stack is empty
else // stack is not empty
{
System.out.print( "stack contains: " );

// iterate through the elements


for ( Number number : stack )
System.out.printf( "%s ", number );

System.out.print( "(top) \n\n" ); // indicates top of the stack


} // end else
} // end method printStack

public static void main( String args[] )


{
new StackTest();
} // end main
} // end class StackTest

Map
Interfaţa Map descrie structuri de date ce asociază fiecărui element o cheie unică, după
care poate fi regăsit. Obiectele de acest tip nu pot conţine chei duplicate şi fiecare cheie este
asociată la un singur element. Ierarhia interfeţelor derivate din Map este independentă de
ierarhia derivată din Collection.

public interface Map {


// Metode cu caracter general
int size();
boolean isEmpty();
void clear();
// Operatii la nivel de element
Object put(Object key, Object value);
Object get(Object key);
Object remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
// Operatii la nivel de multime
void putAll(Map t);
// Vizualizari ale colectiei
public Set keySet();
public Collection values();
public Set entrySet();
// Interfata pentru manipularea unei inregistrari
public interface Entry {
Object getKey();
Object getValue();
Object setValue(Object value);
}
}

16
Clase care implementează interfaţa Map sunt HashMap, TreeMap şi Hashtable.

SortedMap
Interfaţa SortedMap este asemănătoare cu interfaţa Map, la care se adaugă faptul că
mulţimea cheilor dintr-o astfel de colecţie este menţinută ordonată ascendent conform ordinii
naturale, sau conform cu ordinea dată de un comparator specificat la crearea colecţiei. Este
subclasa a interfeţei Map, oferind metode suplimentare pentru: extragere de subtabele, aflarea
primei/ultimei chei, aflarea comparatorului folosit pentru ordonare.

public interface SortedMap extends Map {


// Extragerea de subtabele
SortedMap subMap(Object fromKey, Object toKey);
SortedMap headMap(Object toKey);
SortedMap tailMap(Object fromKey);
// Capete
Object first();
Object last();
// Comparatorul folosit pentru ordonare
Comparator comparator();
}
Clasa care implementează această interfaţă este TreeMap.

Exemplu. Un program care contorizează apariţiile cuvintelor dintr-un text.

import java.util.StringTokenizer;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.Scanner;

public class WordTypeCount


{
private Map< String, Integer > map;
private Scanner scanner;

public WordTypeCount()
{
map = new HashMap< String, Integer >(); // create HashMap
scanner = new Scanner( System.in ); // create scanner
createMap(); // create map based on user input
displayMap(); // display map content
} // end WordTypeCount constructor

// create map from user input


private void createMap()
{
System.out.println( "Enter a string:" ); // prompt for user input
String input = scanner.nextLine();

// create StringTokenizer for input


StringTokenizer tokenizer = new StringTokenizer( input );

// processing input text


while ( tokenizer.hasMoreTokens() ) // while more input
{
String word = tokenizer.nextToken().toLowerCase(); // get word

17
// if the map contains the word
if ( map.containsKey( word ) ) // is word in map
{
int count = map.get( word ); // get current count
map.put( word, count + 1 ); // increment count
} // end if
else
map.put( word, 1 ); // add new word with a count of 1 to map
} // end while
} // end method createMap

// display map content


private void displayMap()
{
Set< String > keys = map.keySet(); // get keys

// sort keys
TreeSet< String > sortedKeys = new TreeSet< String >( keys );

System.out.println( "Map contains:\nKey\t\tValue" );

// generate output for each key in map


for ( String key : sortedKeys )
System.out.printf( "%-10s%10s\n", key, map.get( key ) );

System.out.printf(
"\nsize:%d\nisEmpty:%b\n", map.size(), map.isEmpty() );
} // end method displayMap

public static void main( String args[] )


{
new WordTypeCount();
} // end main
} // end class WordTypeCount

Auto-boxing la colecții
O colecție conține doar obiecte nu și elemente de tip primitiv de date. Pentru tipuri primitive
de date se pot folosi vectori, dar aceștia sunt de dimensiune fixă. Pentru a adăuga un element de
tip primitiv într-o colecție trebuie înfășurat (warp) tipul primitiv într-o clasa wrapper, precum
Integer, Double, etc.

Prin auto-boxing această problemă se rezolvă ca în exemplul următor:

Integer intObj = 1234; // autobox de la int la Integer


int i = intObj; // auto-unbox de la Integer la int

Double doubleObj = 11.12; // autoboxing de la double la Double


double d = doubleObj; // atuo-unbox de la Double la double

Exemplu. Autoboxing cu genericitate și for-each.

18
import java.util.*;

public class PrimitiveCollectionTest {


public static void main(String[] args) {
List<Integer> aList = new ArrayList<Integer>();

// adauga primitive int de la 1 la 10


for (int i = 1; i <= 10; i++)
aList.add(i); // autobox la Integer,
// upcast la Object, compiler type-check

// parcurgere cu for si index


for (int i=0; i<aList.size(); i++) {
int j = aList.get(i); // downcast la Integer de catre compilator,
// autounbox la int, type-safe
System.out.println(j);
}

// parcurgere cu iterator
Iterator<Integer> iter = aList.iterator();
while (iter.hasNext()) {
int i = iter.next(); // downcast la Integer de catre compilator,
// autounbox la int, type-safe
System.out.println(i);
}

// parcurgere cu bucla for-each


for (int i : aList) { // downcast la Integer de catre compilator,
// autounbox la int, type-safe
System.out.println(i);
}
}
}

19