Che cos’è un tipo grezzo e perché non dovremmo usarlo?

Domande:

  • Quali sono i tipi non elaborati in Java e perché sento spesso che non dovrebbero essere utilizzati nel nuovo codice?
  • Qual è l’alternativa se non possiamo usare i tipi grezzi e come è meglio?

Cos’è un tipo raw?

La specifica del linguaggio Java definisce un tipo non elaborato come segue:

Tipi grezzi di JLS 4.8

Un tipo non elaborato è definito come uno di:

  • Il tipo di riferimento che si forma assumendo il nome di una dichiarazione di tipo generica senza un elenco di argomenti di tipo associato.

  • Un tipo di matrice il cui tipo di elemento è un tipo non elaborato.

  • Un tipo di membro non static di un tipo R non ereditato da una superclass o superinterfaccia di R

Ecco un esempio per illustrare:

 public class MyType { class Inner { } static class Nested { } public static void main(String[] args) { MyType mt; // warning: MyType is a raw type MyType.Inner inn; // warning: MyType.Inner is a raw type MyType.Nested nest; // no warning: not parameterized type MyType mt1; // no warning: type parameter given MyType mt2; // no warning: type parameter given (wildcard OK!) } } 

Qui, MyType è un tipo parametrizzato ( JLS 4.5 ). È comune riferirsi colloquialmente a questo tipo come semplicemente MyType in breve, ma tecnicamente il nome è MyType .

mt ha un tipo raw (e genera un avviso di compilazione) dal primo punto elenco nella definizione sopra; inn ha anche un tipo grezzo dal terzo punto elenco.

MyType.Nested non è un tipo parametrico, anche se è un tipo membro di un tipo parametrico MyType , perché è static .

mt1 e mt2 sono entrambi dichiarati con parametri di tipo effettivi, quindi non sono tipi non mt1 .


Cosa c’è di così speciale nei tipi raw?

Essenzialmente, i tipi grezzi si comportano esattamente come prima dell’avvento dei generici. Cioè, il seguente è del tutto legale in fase di compilazione.

 List names = new ArrayList(); // warning: raw type! names.add("John"); names.add("Mary"); names.add(Boolean.FALSE); // not a compilation error! 

Il codice sopra riportato funziona bene, ma si supponga di avere anche quanto segue:

 for (Object o : names) { String name = (String) o; System.out.println(name); } // throws ClassCastException! // java.lang.Boolean cannot be cast to java.lang.String 

Ora ci imbattiamo in problemi in fase di esecuzione, perché i names contengono qualcosa che non è instanceof String .

Presumibilmente, se vuoi che i names contengano solo String , potresti ancora utilizzare un tipo non elaborato e controllare manualmente ogni add , quindi lanciare manualmente su String ogni elemento dai names . Ancora meglio , anche se NON è di usare un tipo grezzo e lasciare che il compilatore faccia tutto il lavoro per voi , sfruttando la potenza dei generici Java.

 List names = new ArrayList(); names.add("John"); names.add("Mary"); names.add(Boolean.FALSE); // compilation error! 

Naturalmente, se si desidera che i names consentano un Boolean , è ansible dichiararlo come nome Listnames e il codice sopra riportato verrà compilato.

Guarda anche

  • Esercitazioni Java / generici

Come è diverso un tipo non elaborato dall’utilizzo di come parametri del tipo?

Quanto segue è una citazione di Effective Java 2nd Edition, Articolo 23: Non utilizzare i tipi non elaborati nel nuovo codice :

Qual è la differenza tra l’ List tipi non List e il tipo di List parametrizzato List ? In poche parole, il primo ha distriggersto il controllo di tipo generico, mentre il secondo ha esplicitamente detto al compilatore che è in grado di contenere oggetti di qualsiasi tipo. Mentre è ansible passare un List a un parametro di tipo List , non è ansible passarlo a un parametro di tipo List . Esistono regole di sottotipizzazione per i generici e List è un sottotipo List tipi non List , ma non del tipo parametrizzato List . Di conseguenza, si perde la sicurezza del tipo se si utilizza il tipo non elaborato come List , ma non se si utilizza un tipo parametrizzato come List .

Per illustrare il punto, prendere in considerazione il seguente metodo che accetta un List e aggiunge un new Object() .

 void appendNewObject(List list) { list.add(new Object()); } 

I generici in Java sono invarianti. Un List non è un List , pertanto quanto segue genererebbe un avviso del compilatore:

 List names = new ArrayList(); appendNewObject(names); // compilation error! 

Se avessi dichiarato appendNewObject di prendere come parametro un List tipo non appendNewObject , questo sarebbe compilato, e quindi perderai il tipo di sicurezza che ricevi dai generici.

Guarda anche

  • Qual è la differenza tra e ?
  • java generics (non) covarianza

In che modo un tipo non elaborato è diverso dall’uso di Come parametro di tipo?

List , List , ecc. Sono tutti List , Quindi potrebbe essere tentato di dire semplicemente che sono solo List . Tuttavia, c’è una grande differenza: poiché un List definisce solo add(E) , non è ansible aggiungere un qualsiasi object arbitrario a un List . D’altra parte, dal momento che la List tipo non ha tipo sicurezza, è ansible add qualsiasi cosa a un List .

Considera la seguente variante del frammento precedente:

 static void appendNewObject(List list) { list.add(new Object()); // compilation error! } //... List names = new ArrayList(); appendNewObject(names); // this part is fine! 

Il compilatore ha fatto un ottimo lavoro nel proteggerti dal potenziale violare l’invarianza di tipo List ! Se il parametro è stato dichiarato come List list tipi non List list , il codice verrebbe compilato e violerebbe il tipo invariante dei List names di List names .


Un tipo non elaborato è la cancellazione di quel tipo

Torna a JLS 4.8:

È ansible utilizzare come tipo la cancellazione di un tipo parametrico o la cancellazione di un tipo di matrice il cui tipo di elemento è un tipo parametrizzato. Un tal tipo è chiamato un tipo crudo .

[…]

Le superclassi (rispettivamente le superinterfacce) di un tipo grezzo sono le cancellature delle superclassi (superinterfacce) di una qualsiasi delle parametrizzazioni del tipo generico.

Il tipo di un costruttore, un metodo di istanza o static campo non static di un tipo non elaborato C che non è ereditato dalle sue superclassi o superinterfacce è il tipo non elaborato che corrisponde alla cancellazione del suo tipo nella dichiarazione generica corrispondente a C

In termini più semplici, quando viene utilizzato un tipo non static , vengono cancellati anche i costruttori, i metodi di istanza e static campi non static .

Prendi il seguente esempio:

 class MyType { List getNames() { return Arrays.asList("John", "Mary"); } public static void main(String[] args) { MyType rawType = new MyType(); // unchecked warning! // required: List found: List List names = rawType.getNames(); // compilation error! // incompatible types: Object cannot be converted to String for (String str : rawType.getNames()) System.out.print(str); } } 

Quando usiamo il MyType getNames , anche getNames viene cancellato, in modo che restituisca una List getNames !

JLS 4.6 continua a spiegare quanto segue:

La cancellazione dei tipi associa anche la firma di un costruttore o di un metodo a una firma che non ha tipi parametrizzati o variabili di tipo. La cancellazione di un costruttore o di una firma del metodo è una firma composta dallo stesso nome di s e dalle cancellature di tutti i tipi di parametri formali dati in s .

Anche il tipo restituito di un metodo e i parametri di tipo di un metodo o costruttore generico subiscono la cancellazione se il metodo o la firma del costruttore vengono cancellati.

La cancellazione della firma di un metodo generico non ha parametri di tipo.

La seguente segnalazione contiene alcuni pensieri di Maurizio Cimadamore, uno sviluppatore di compilatori e Alex Buckley, uno degli autori del JLS, sul motivo per cui questo tipo di comportamento dovrebbe verificarsi: https://bugs.openjdk.java.net/browse / JDK-6400189 . (In breve, rende le specifiche più semplici).


Se non è sicuro, perché è consentito utilizzare un tipo non elaborato?

Ecco un’altra citazione da JLS 4.8:

L’uso di tipi grezzi è consentito solo come concessione alla compatibilità del codice legacy. L’uso di tipi grezzi nel codice scritto dopo l’introduzione della genericità nel linguaggio di programmazione Java è fortemente scoraggiato. È ansible che le versioni future del linguaggio di programmazione Java non consentano l’uso di tipi non elaborati.

Anche la 2a Edizione Java efficace ha aggiunto:

Dato che non si dovrebbero usare i tipi non elaborati, perché i progettisti linguistici li hanno autorizzati? Per fornire compatibilità.

La piattaforma Java stava per entrare nel suo secondo decennio quando furono introdotti i generici, e esisteva un’enorme quantità di codice Java che non usava i generici. È stato ritenuto fondamentale che tutto questo codice rimanga legale e interoperabile con un nuovo codice che usi i generici. Doveva essere legale passare le istanze di tipi parametrici a metodi che erano stati progettati per l’uso con tipi ordinari e viceversa. Questo requisito, noto come compatibilità della migrazione , ha guidato la decisione di supportare i tipi di dati non elaborati.

In sintesi, i tipi raw non dovrebbero MAI essere usati nel nuovo codice. Dovresti sempre usare tipi parametrizzati .


Non ci sono eccezioni?

Sfortunatamente, poiché i generici Java non sono reificati, ci sono due eccezioni dove i tipi grezzi devono essere usati nel nuovo codice:

  • List.class class, ad es. List.class , non List.class
  • instanceof operando, ad esempio o instanceof Set , non o instanceof Set

Guarda anche

  • Perché Collection.class illegale?

Quali sono i tipi non elaborati in Java e perché sento spesso che non dovrebbero essere utilizzati nel nuovo codice?

I tipi grezzi sono una storia antica del linguaggio Java. All’inizio c’erano le Collections e non contenevano Objects niente di più e niente di meno. Ogni operazione su Collections richiede cast da Object al tipo desiderato.

 List aList = new ArrayList(); String s = "Hello World!"; aList.add(s); String c = (String)aList.get(0); 

Mentre questo ha funzionato la maggior parte del tempo, gli errori sono accaduti

 List aNumberList = new ArrayList(); String one = "1";//Number one aNumberList.add(one); Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here 

Le vecchie raccolte senza tipo non potevano imporre la sicurezza del tipo, quindi il programmatore doveva ricordare cosa memorizzava all’interno di una raccolta.
Generics dove inventato per aggirare questa limitazione, lo sviluppatore dichiarerebbe il tipo memorizzato una volta e il compilatore lo farebbe invece.

 List aNumberList = new ArrayList(); aNumberList.add("one"); Integer iOne = aNumberList.get(0);//Compile time error String sOne = aNumberList.get(0);//works fine 

Per confronto:

 // Old style collections now known as raw types List aList = new ArrayList(); //Could contain anything // New style collections with Generics List aList = new ArrayList(); //Contains only Strings 

Più complessa l’interfaccia Compradible:

 //raw, not type save can compare with Other classs class MyCompareAble implements CompareAble { int id; public int compareTo(Object other) {return this.id - ((MyCompareAble)other).id;} } //Generic class MyCompareAble implements CompareAble { int id; public int compareTo(MyCompareAble other) {return this.id - other.id;} } 

Si noti che è imansible implementare l’interfaccia compareTo(MyCompareAble) con compareTo(MyCompareAble) con i tipi non compareTo(MyCompareAble) . Perché non dovresti usarli:

  • Qualsiasi Object memorizzato in una Collection deve essere lanciato prima di poter essere utilizzato
  • L’uso di generics consente di controllare i tempi di compilazione
  • L’utilizzo di tipi non elaborati equivale alla memorizzazione di ciascun valore come Object

Cosa fa il compilatore: Generics è compatibile con le versioni precedenti, usano le stesse classi java dei tipi non elaborati. La magia accade principalmente al momento della compilazione.

 List someStrings = new ArrayList(); someStrings.add("one"); String one = someStrings.get(0); 

Sarà compilato come:

 List someStrings = new ArrayList(); someStrings.add("one"); String one = (String)someStrings.get(0); 

Questo è lo stesso codice che scriveresti se usassi direttamente i tipi grezzi. Ho pensato che non sono sicuro di cosa succede con l’interfaccia CompareAble , immagino che crei due funzioni di confronto, una che prende MyCompareAble e l’altra che prende un Object e lo passa al primo dopo averlo lanciato.

Quali sono le alternative ai tipi non elaborati : usa i generici

Un tipo non elaborato è il nome di una class o interfaccia generica senza argomenti di tipo. Ad esempio, data la class Box generica:

 public class Box { public void set(T t) { /* ... */ } // ... } 

Per creare un tipo parametrizzato di Box , si fornisce un argomento di tipo effettivo per il parametro di tipo formale T :

 Box intBox = new Box<>(); 

Se l’argomento di tipo attuale è omesso, si crea un tipo non elaborato di Box :

 Box rawBox = new Box(); 

Pertanto, Box è il tipo non elaborato del tipo generico Box . Tuttavia, una class non generica o un tipo di interfaccia non è un tipo non elaborato.

I tipi non elaborati vengono visualizzati nel codice precedente poiché molte classi API (come le classi Raccolte) non erano generiche prima di JDK 5.0. Quando si utilizzano i tipi non elaborati, si ottiene essenzialmente un comportamento pre-generico: una Box fornisce Object . Per compatibilità con le versioni precedenti, l’assegnazione di un tipo parametrizzato al tipo non elaborato è consentita:

 Box stringBox = new Box<>(); Box rawBox = stringBox; // OK 

Ma se assegni un tipo non elaborato a un tipo parametrizzato, ricevi un avvertimento:

 Box rawBox = new Box(); // rawBox is a raw type of Box Box intBox = rawBox; // warning: unchecked conversion 

Viene visualizzato anche un avviso se si utilizza un tipo non elaborato per richiamare i metodi generici definiti nel tipo generico corrispondente:

 Box stringBox = new Box<>(); Box rawBox = stringBox; rawBox.set(8); // warning: unchecked invocation to set(T) 

L’avviso mostra che i tipi non elaborati ignorano i controlli di tipo generico, rinviando la cattura di codice non sicuro al runtime. Pertanto, dovresti evitare di utilizzare i tipi non elaborati.

La sezione sulla cancellazione dei tipi contiene ulteriori informazioni su come il compilatore Java utilizza i tipi non elaborati.

Messaggi di errore non controllati

Come accennato in precedenza, quando si mischia codice legacy con codice generico, è ansible che si verifichino messaggi di avviso simili ai seguenti:

Nota: Example.java utilizza operazioni non controllate o non sicure.

Nota: ricompilare con -Xlint: deselezionato per i dettagli.

Questo può accadere quando si utilizza un’API precedente che opera su tipi non elaborati, come mostrato nell’esempio seguente:

 public class WarningDemo { public static void main(String[] args){ Box bi; bi = createBox(); } static Box createBox(){ return new Box(); } } 

Il termine “deselezionato” significa che il compilatore non ha abbastanza informazioni sul tipo per eseguire tutti i controlli di tipo necessari per garantire la sicurezza del tipo. L’avviso “deselezionato” è disabilitato, di default, sebbene il compilatore fornisca un suggerimento. Per vedere tutti gli avvertimenti “non controllati”, ricompilare con -Xlint: deselezionato.

La ricompilazione dell’esempio precedente con -Xlint: deselezionato rivela le seguenti informazioni aggiuntive:

 WarningDemo.java:4: warning: [unchecked] unchecked conversion found : Box required: Box bi = createBox(); ^ 1 warning 

Per disabilitare completamente gli avvisi non selezionati, utilizzare il flag -Xlint: -unchecked. L’ @SuppressWarnings("unchecked") sopprime gli avvertimenti deselezionati. Se non si ha familiarità con la syntax @SuppressWarnings , consultare Annotazioni.

Fonte originale: tutorial Java

  private static List list = new ArrayList(); 

Dovresti specificare il parametro type.

L’avvertimento indica che i tipi definiti per supportare i generici dovrebbero essere parametrizzati, piuttosto che usare la loro forma grezza.

List è definito per supportare i generici: public class List . Ciò consente molte operazioni di sicurezza del tipo, che vengono controllate in fase di compilazione.

Un tipo “raw” in Java è una class che non è generica e si occupa di oggetti “grezzi”, piuttosto che di parametri di tipo generico sicuri per tipo.

Ad esempio, prima che i generici Java fossero disponibili, si userebbe una class di raccolta come questa:

 LinkedList list = new LinkedList(); list.add(new MyObject()); MyObject myObject = (MyObject)list.get(0); 

Quando aggiungi il tuo object alla lista, non gli interessa quale tipo di object è, e quando lo ottieni dalla lista, devi lanciarlo esplicitamente al tipo che ti aspetti.

Usando i generici, rimuovi il fattore “sconosciuto”, perché devi esplicitamente specificare quale tipo di oggetti può andare nella lista:

 LinkedList list = new LinkedList(); list.add(new MyObject()); MyObject myObject = list.get(0); 

Si noti che con i generici non è necessario eseguire il cast dell’object proveniente dalla chiamata get, la raccolta è predefinita per funzionare solo con MyObject. Questo fatto è il principale fattore trainante per i generici. Cambia una fonte di errori di runtime in qualcosa che può essere controllato in fase di compilazione.

Che cos’è un tipo grezzo e perché sento spesso che non dovrebbero essere utilizzati in un nuovo codice?

Un “tipo grezzo” è l’uso di una class generica senza specificare un argomento di tipo per i suoi tipi parametrici, ad esempio usando List invece di List . Quando i generici sono stati introdotti in Java, diverse classi sono state aggiornate per utilizzare i generici. L’utilizzo di queste classi come “tipo non elaborato” (senza specificare un argomento di tipo) ha consentito al codice legacy di essere ancora compilato.

I “tipi grezzi” sono usati per la retrocompatibilità. Il loro uso nel nuovo codice non è raccomandato perché l’uso della class generica con un argomento di tipo consente una digitazione più forte, che a sua volta può migliorare la comprensibilità del codice e portare a rilevare potenziali problemi in precedenza.

Qual è l’alternativa se non possiamo usare i tipi grezzi e come è meglio?

L’alternativa preferita è usare le classi generiche come previsto – con un argomento di tipo adatto (ad es. List ). Ciò consente al programmatore di specificare i tipi in modo più specifico, conferisce maggiore significato ai futuri manutentori circa l’uso previsto di una variabile o di una struttura dati e consente al compilatore di imporre una migliore sicurezza del tipo. Questi vantaggi insieme possono migliorare la qualità del codice e aiutare a prevenire l’introduzione di alcuni errori di codifica.

Ad esempio, per un metodo in cui il programmatore desidera assicurarsi che una variabile List chiamata “nomi” contenga solo stringhe:

 List names = new ArrayList(); names.add("John"); // OK names.add(new Integer(1)); // compile error 

Il compilatore vuole che tu scriva questo:

 private static List list = new ArrayList(); 

perché altrimenti, è ansible aggiungere qualsiasi tipo desiderato list , rendendo inutile l’istanza come new ArrayList() . I generici Java sono solo una funzione in fase di compilazione, quindi un object creato con la new ArrayList() accetterà volentieri gli elementi Integer o JFrame se assegnati a un riferimento della List “tipo raw” – l’object stesso non sa nulla su quali tipi dovrebbe contenere, solo il compilatore.

Qui sto considerando diversi casi attraverso i quali puoi chiarire il concetto

 1. ArrayList arr = new ArrayList(); 2. ArrayList arr = new ArrayList(); 3. ArrayList arr = new ArrayList(); 

Caso 1

ArrayList arr it è una variabile di riferimento ArrayList con tipo String che fa riferimento a un object ArralyList di tipo String . Significa che può contenere solo oggetti di tipo stringa.

È un Strict to String non di tipo Raw quindi, non genererà mai un avviso.

  arr.add("hello");// alone statement will compile successfully and no warning. arr.add(23); //prone to compile time error. //error: no suitable method found for add(int) 

Caso 2

In questo caso ArrayList arr è un tipo strict ma il tuo Object new ArrayList(); è un tipo grezzo.

  arr.add("hello"); //alone this compile but raise the warning. arr.add(23); //again prone to compile time error. //error: no suitable method found for add(int) 

qui arr è un tipo rigoroso. Quindi, aumenterà l’errore di compilazione durante l’aggiunta di un integer .

Avviso : – Un object di tipo non elaborato fa riferimento a un tipo Strict Variabile di riferimento di ArrayList .

Caso 3

In questo caso ArrayList arr è un tipo non elaborato ma il tuo object new ArrayList(); è un tipo rigoroso.

  arr.add("hello"); arr.add(23); //compiles fine but raise the warning. 

Aggiungerà qualsiasi tipo di object in esso perché arr è un tipo non arr .

Avvertenza : – Un object di tipo Strict fa riferimento a una variabile referenziata di tipo non elaborato.

Un tipo- grezzo è la mancanza di un parametro di tipo quando si utilizza un tipo generico.

Raw-type non dovrebbe essere usato perché potrebbe causare errori di runtime, come l’inserimento di un double in quello che doveva essere un Set di int s.

 Set set = new HashSet(); set.add(3.45); //ok 

Quando recuperi le cose dal Set , non sai cosa sta uscendo. Supponiamo che ti aspetti che sia tutto int , lo stai trasmettendo a Integer ; eccezione al runtime quando arriva il double 3.45.

Con un parametro di tipo aggiunto al tuo Set , riceverai un errore di compilazione in una volta. Questo errore preventivo ti consente di risolvere il problema prima che qualcosa esploda durante il runtime (risparmiando così tempo e fatica).

 Set set = new HashSet(); set.add(3.45); //NOT ok. 

Quello che sta dicendo è che la tua list è una List di oggetti non specificati. Quello è che Java non sa che tipo di oggetti sono all’interno della lista. Quindi, quando vuoi iterare la lista devi castare ogni elemento, per poter accedere alle proprietà di quell’elemento (in questo caso, String).

In generale è un’idea migliore per parametrizzare le raccolte, in modo da non avere problemi di conversione, sarai solo in grado di aggiungere elementi del tipo parametrizzato e il tuo editore ti offrirà i metodi appropriati da selezionare.

 private static List list = new ArrayList(); 

pagina tutorial .

Un tipo non elaborato è il nome di una class o interfaccia generica senza argomenti di tipo. Ad esempio, data la class Box generica:

 public class Box { public void set(T t) { /* ... */ } // ... } 

Per creare un tipo di Box parametrizzato, si fornisce un argomento di tipo effettivo per il parametro di tipo formale T:

 Box intBox = new Box<>(); 

Se l’argomento di tipo attuale è omesso, si crea un tipo non elaborato di Box:

 Box rawBox = new Box(); 

Ecco un altro caso in cui i tipi non elaborati ti mordono:

 public class StrangeClass { @SuppressWarnings("unchecked") public  X getSomethingElse() { return (X)"Testing something else!"; } public static void main(String[] args) { final StrangeClass withGeneric = new StrangeClass<>(); final StrangeClass withoutGeneric = new StrangeClass(); final String value1, value2; // Works value1 = withGeneric.getSomethingElse(); // Produces compile error: // incompatible types: java.lang.Object cannot be converted to java.lang.String value2 = withoutGeneric.getSomethingElse(); } } 

Come è stato menzionato nella risposta accettata, perdi tutto il supporto per i generici all’interno del codice del tipo non elaborato. Ogni parametro di tipo viene convertito nella sua cancellazione (che nell’esempio precedente è solo Object ).

Ho trovato questa pagina dopo aver fatto alcuni esempi di esercizi e avendo la stessa identica perplessità.

============== Sono passato da questo codice come fornito dal campione ===============

 public static void main(String[] args) throws IOException { Map wordMap = new HashMap(); if (args.length > 0) { for (int i = 0; i < args.length; i++) { countWord(wordMap, args[i]); } } else { getWordFrequency(System.in, wordMap); } for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); System.out.println(entry.getKey() + " :\t" + entry.getValue()); } 

====================== A questo codice ========================

 public static void main(String[] args) throws IOException { // replace with TreeMap to get them sorted by name Map wordMap = new HashMap(); if (args.length > 0) { for (int i = 0; i < args.length; i++) { countWord(wordMap, args[i]); } } else { getWordFrequency(System.in, wordMap); } for (Iterator> i = wordMap.entrySet().iterator(); i.hasNext();) { Entry entry = i.next(); System.out.println(entry.getKey() + " :\t" + entry.getValue()); } } 

================================================== =============================

Potrebbe essere più sicuro, ma ci sono volute 4 ore per accontentare la filosofia ...

I tipi grezzi vanno bene quando esprimono ciò che vuoi esprimere.

Ad esempio, una funzione di deserializzazione potrebbe restituire un List , ma non conosce il tipo di elemento dell’elenco. Quindi List è il tipo di ritorno appropriato qui.