PDA

View Full Version : [JAVA] Problema in compilazione, messaggio di attenzione operazione insicura, perchè?


e-commerce84
03-06-2009, 10:39
Ciao,
stò scrivendo questa classe Java chiamata Involucro che gestisce una collezione di stringhe rappresentate con un Vector.
Le stringhe accettate dalla collezione hanno la particolarità che la i-esima stringa deve sempre essere contenuta nella (i+1)-esima stringa.

Quindi saranno collezioni del tipo: {a, ab, abc, z[B]abc]u} tanto per fare un esempio.

Per ora ho scritto solo il costruttore ed un metodo che aggiunge un elemento alla collezione, tale secondo metodo controlla se la collezione è vuota ci inserisce una stringa ricevuta come parametro, se invece la collezione non è vuota controlla se l'ultimo elemento della collezione è contenuto nel parametro e se è vero lo aggiunge, altrimenti solleva un'eccezione...però mi dà uno strano messaggio in compilazione.

Il codice è questo:

Classe Involucro (c'è un sacco di documentazione ma quella è perchè piace alla proff, in realtà sono 3 righe di codice):

import java.util.*;

public class Involucro{
/** OVERVIEW: Involucro rappresenta una collezione dinamica di stringhe del tipo <s1, s2, s3,...., sn> tali che
s_i è completamente contenuta in s_(i+1).

V = {{s1,s2,s3,...,sn>: Per ogni i s_i è una stringa ed s_i è interamente contenuto in s_(i+1)}}

O = inserisci: Se l'oggetto che si vuole inserire è coerente con la rappresentazione della collezione
(è una stringa) e con lo stato attuale della collezione (i valori già presenti nella
collezione), allora lo inserisce nella collezione modificandola

fondi: Date collezioni S e T se s_n è interamente contenuto in t_1 allora fonde le due collezioni nel
seguente modo: S = <s1,s2,s3,...,sn> T = {t1,t2,t3,...,tn} --> {s1,s2,s3,...,sn,t1,t2,t3,..,tn}

get(i): Accede in maniera posizionale all'i-esimo elemento della collezione */

Vector collStr; // Rappresenta la collezione di stringhe


/** FUNZIONE DI ASTRAZIONE: F_a(): STATO CONCRETO ----> STATO ASTRATTO
F_a([a, ab, abc, abcd]) ------> {<a, ab, abc, abcd>}
ma anche: F_a([a, b(a), (ba)f, z(baf), (zbaf)e]) ---> {a, ba, baf, zbaf, zbafe}

INVARIANTE DI RAPPRESENTAZIONE: è un predicato I: C ---> boolean che è vero per gli stati concreti che sono
rappresentazioni leggittime di uno stato astratto:

I(collStr): collStr != NULL (il Vector deve essere sempre diverso da NULL)
Per ogni i: v.get(i) deve essere incluso in v.get(i+1) (la i-esima stringa deve
sempre essere interamente contenuta nella (i+1)-esima stringa della collezione */

/** COSTRUTTORE:
EFFECTS: Crea un nuovo oggetto di tipo Involucro che rappresenta la collezione vuota
@param: void:
@return: Il riferimento ad un oggetto di tipo Involucro
Il costruttore soddisfa l'invariante di rappresentazione in quanto: 1) Viene assegnata alla variabile di istanza
collStr il riferimento ad un nuovo Vector quindi no è mai null. 2) Il costruttore crea una collezione vuota che
rappresenta la stringa vuota contenuta in ogni stringa, quindi qualsiasi sia il primo elemento va bene */

public Involucro(){
collStr = new Vector(); // Crea la collezione vuota assegnando a collStr il riferimento ad un nuovo Vector vuoto
}

/** Metodo inserisci()
EFFECTS: Se il parametro può essere inserito nella collezione (se contiene completamente l'ultima stringa della
collezione, allora viene inserito nella collezione rappresentata dall'oggetto ricevente, altrimenti viene
sollevata una StringaNonValidaException
MODIFIES: this
@param: Un oggetto di tipo String
Il metodo inserisci() soddisfa l'invariante di rappresentazione in quanto se la collezione è vuota permette
l'inserimento di una stringa qualsiasi, se invece nella collezione è già presente qualcosa prima di inserire il
parametro controlla che il parametro contiene completamente l'ultima stringa presente nella collezione. Se ciò è
verificato la inserisce, altrimenti no e la collezione rimane sempre coerente con la sua definizione */

public void inserisci(String str){

int dimensione = collStr.size() ; // Contiene la dimensione del Vector collStr
if(dimensione == 0) // Se la collezione è vuota
collStr.addElement(str); // Aggiungi la stringa parametro in prima posizione

else{ // Altrimenti, se nella collezione ci sono già degli elementi
if(str.contains(collStr.elementAt(dimensione))) // Se i parametro contiene l'ultima stringa della collezione
collStr.addElement(str); // Aggiungi la stringa parametro in prima posizione
else throw new StringaNonValidaException(); // altrimenti solleva un'eccezione
}
}
}


Eccezione:

public class StringaNonValidaException extends RuntimeException{

public StringaNonValidaException(){
super();
}

public StringaNonValidaException(String s){
super(s);
}
}


Il messaggio di errore è il seguente:

C:\Programmi\Crimson Editor\template\esercizi\esami\11-07-07>javac Involucro.java
Note: Involucro.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

A cosa si riferisce? Che problemi può creare? Soluzioni?

Grazie
Andrea

banryu79
03-06-2009, 11:52
Messaggio di warning presente da Java 5 in poi per via della presenza dei Generics; se nel codice si fa uso di collezioni senza lo specificatore di tipo il compilatore ricorda che, per l'appunto, non è in grado di controllare che la collezione sia usata in modo "type-safe".

Esempio di una collezione (List) di String usata in modo non type-safe:

// crea lista (di String?)
List myList = new ArrayList();

// inserico un po' di String
// bla bla...


// ...più tardi
// recupero (una String?)
String maybe = (String) myList.get(0);


Esempio di una collezione (List) di String usata in modo type-safe:

// crea lista [di String!]
List<String> myList = new ArrayList<String>();

// inserico un po' di String
// bla bla...


// ...più tardi
// recupero [una String!]
String sure = myList.get(0);


Piccolo bonus aggiuntivo: se usi la versione "type-safe" (quella che, tramite lo specificatore di tipo fa uso dei Generics) puoi usare il costrutto for in versione più snella (a livello di codice da scrivere)

for (String s : myList)
{
System.out.println(s);
}

Funziona solo da Java 5, con collezioni che fanno uso dei Generics.
In pratica usa in maniera trasparente un Iterator per recuperare un elemento per ciclo nella lista.


Dimenticavo...

Che problemi può creare?

Se usi una collection senza specificatore di tipo da Java 5 in poi hai gli stessi problemi che si avevano prima che introducessero i Generics nel linguaggio: cioè nessun 'problema' in senso stretto.
Semplicemente la tua collection resta una collection di Object e non di un tipo spefico; quando da codice ci infili dentro, che so, java.awt.Rectangle (per esempio) al momento della restituzione di un elemento la collection restituirà un Object: sei tu che lo devi sapere e che fai il cast a mano al giusto tipo.
Il compilatore semplicemente non è in grado di controllare che tu stia facendo la "giusta" operazione di casting, e quindi ti stampa il warning per comunicartelo.
Inoltre se in una collezione il cui tipo specifico è stato specificato, per esempio, come String, tu provi ad infilarci qualcosa di tipo non compatibile, il compilatore si arrabbia. Nella versione "non type-safe" semplicemente non c'è questo controllo, o meglio, dato che tutti gli oggetti in Java estendono implicitamente Object, il loro inserimento è sempre valido; vengono discriminati solo i tipi primitivi del linguaggio.

e-commerce84
03-06-2009, 18:21
mmm capisco...noi a lezione non abbiamo trattato i generics...ho capito di cosa si tratta e a cosa servono...appena ho un po' di tempo libero gli darò un'occhiata approfondita :)

Questa è una parte di un compito d'esame...praticamente il testo diceva di progettare ed implementare questa classe Involucro che rappresenta collezioni di stringhe particolari come specificato nel primo post ed implementa le seguenti 3 operazioni:

1) Inserimento di una stringa in un oggetto di tipo Involucro (se possibile) con modifica dell'oggetto ricevente

2) Fusione di due oggetti <s1,s2,s3,...,sn> e <t1,t2,t3,...,tn> creando (se possibile) un nuovo oggetto di tipo Involucro: <s1,s2,s3,...,sn,t1,t2,t3,....tn>

3) Accesso in lettura alla collezione

Io l'ho risolto così, dici che è una soluzione che va bene? (c'è tanta documentazione perchè la proff la vuole...maalla fine sono poche linee di codice)


/* La classe GestoreStringhe è un contenitore di metodi utili per operare sulle stringhe */
public class GestoreStringhe{

/* Metodo che prende due stringhe: nome e cognome; e che le unisce separandole con uno spazio e mettendo in maiuscolo
le due iniziali ed in minuscolotutto il resto.
Es: nome: "maRiO", cognome: "rOSsi" --> s = "Mario Rossi" */

public static String trasformaInUna(String nome, String cognome){
String s;

s = nome.substring(0,1).toUpperCase();
s += nome.substring(1).toLowerCase();
s += " ";
s += cognome.substring(0,1).toLowerCase()+cognome.substring(1).toLowerCase();

return s;
}

/* Metodo che permette di invertire la stringa che prende come parametro. Es: Se il metodo viene invocato con la stringa
S="Roma", esso restituirà il riferimento all'oggetto di tipo String il cui valore è "amoR" */

public static String invertiStringa(String s){
String t; // Stringa da restituire che conterrà l'inversa della stringa s
int i; // Variabile contatore

t = null; // Inizializzazione: se s è vuota allora verrà restituita la stringa vuota

/* Ciclo che copia in t i caratteri di s a partire dall'ultimo fino al primo */

for(i=s.length()-1; i>=0; i--){ // Per i che parte dalla lunghezza di s meno 1 fino ad aver letto tutti i caratteri
t += s.substring(i,i+1); // Concatena a t l'i-esimo carattere di s
}

return t;
}

/* Metodo che permette di verificare se la stringa che prende come parametro è una stringa palindroma restituendo TRUE
se è vero, FALSE al contrario.
Es: S = "ama" --> restituisce TRUE, S = "ciao" --> restituisce FALSE */

public static boolean verificaPalindromia(String s){

String t; // Conterrà la stringa invertita
t = invertiStringa(s); // Inverte la stringa s e la mette in t

return s.equals(t); // Restituisce il risultato del test di uguaglianza tra s e t che può essere TRUE o FALSE
}

/* Metodo che permette di calcolare il prefisso comune delle due stringhe che prende come parametro */

public static String calcolaPrefissoComune(String s, String t){

int i, min;
boolean trovato; // Diventa TRUE quando si trova un carattere diverso fra s e t
String pref;

if(s.length() < t.length()) min = s.length();

else min = t.length();

trovato = false; // Inizializzazione della variabile trovato a false poichè non è ancora stato trovato un carattere diverso fra s e t
pref = ""; // Inizializzazione delle string pref con la stringa vuota, il prefisso comune è inizialmente nullo
i = 0; // Inizializzazione il contatore a 0

while((i<min) && (!trovato)){ // Finchè il contatore è minore del possibile prefisso e non è stato ancora trovato un carattere diverso fra s e t
if(s.substring(i,i+1).equals(t.substring(i,i+1))){ // Se l'i-esimo carattere delle 2 stringhe è uguale
pref += s.substring(i,i+1); // Concatena a pref l'i-esimo carattere comune alle 2 stringhe
i++; // Incrementa di uno il contatore per andare a testare il prossimo carattere
}
else trovato = true; // Altrimenti impostra trovato a true
}

return pref; // Restituisci il prefisso comune trovato
}
}


Tnx

banryu79
04-06-2009, 09:03
Riporto solo il codice, senza i commenti.

Classe Involucro

import java.util.*;

public class Involucro{

Vector collStr; // Rappresenta la collezione di stringhe

public Involucro(){
collStr = new Vector();
}

public void inserisci(String str){
int dimensione = collStr.size() ;
if(dimensione == 0)
collStr.addElement(str);
else{
if(str.contains(collStr.elementAt(dimensione))) // [1]
collStr.addElement(str);
else throw new StringaNonValidaException(); // [2]
}
}
}

[1]
Se hai già inserito la prima String nel Vector e stai inserendo la seconda, per esempio, il metodo size restituirà 1, valore che viene copiato in 'dimensione'.
Quindi fare: "collStr.elementAt(dimensione)" significa fare "collStr.elementAt(1)" che punta al secondo elemento nel Vector (il primo, quello effettivamente inserito, è 0) ma siccome il secondo elemento ancora non esiste avrai un tentativo di accesso ad un indice non valido a runtime percui dopo aver inserito la prima String nel Vector le successive chiamate al metodo 'inserisci' lancieranno una ArrayIndexOutOfBoundsException.
Questo è un'errore di programmazione, prova a correggerlo.

[2]
L'eccezione definita da te per segnalare il caso in cui la String passata al metodo non è un argomento valido ricalca il significato di un'ecezione già presente nel JDK e che puoi usare: la IllegalArgumentException (ed è una RuntimeException). La trovi nel package java.lang, il package importato di default, quindi è già disponibile. Citando javadoc circa IllegalArgumentException, dice: "Thrown to indicate that a method has been passed an illegal or inappropriate argument.".
Il che ricalca esattamente il motivo d'essere della tua eccezione.


Per GestoreStringhe:

public static String trasformaInUna(String nome, String cognome){
String s;

s = nome.substring(0,1).toUpperCase();
s += nome.substring(1).toLowerCase();
s += " ";
s += cognome.substring(0,1).toLowerCase()+cognome.substring(1).toLowerCase();

return s;
}

La parte in grassetto: credo dovrebbe essere sostituita con 'toUpperCase'.