2010-02-01 12 views
7

Attualmente sto riscoprendo Java (lavorando molto con Ruby di recente) e adoro il controllo in tempo reale di tutto. Rende il refactoring così facile. Tuttavia, mi manca giocare veloce e loose con i tipi per fare un ciclo each. Questo è il mio peggior codice.Trucchi linguistici per abbreviare il mio codice Java?

È il più breve possibile? Ho una raccolta chiamata looperTracks, che ha istanze che implementano Looper. Non voglio modificare quella raccolta, ma voglio scorrere i suoi membri PIÙ il this (che implementa anche Looper).

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1); 
for (LooperTrack track : looperTracks) { 
    allLoopers.add(track); 
} 
allLoopers.add(this); 

for (Looper looper : allLoopers) { 
    // Finally! I have a looper 

Sono particolarmente preoccupato per tutte le funzioni che sono nuovi per Java 1.5 su quel forse ho perso. Per questa domanda sono non chiedendo di JRuby e Groovy, anche se so che avrebbero lavorato per questo.

Edit: (! Troppo Ruby) Siamo spiacenti ... looperTracks è di tipo LooperTrack[] e LooperTrack implementa Looper.

+1

Copiare un elenco solo per poter utilizzare un ciclo for-each è un'idea orribile. In casi come questi non è male fare un'iterazione in due passaggi. – kgiannakakis

+0

Grazie kgiannakakis, fa parte della "preoccupazione" –

+0

Non è una cattiva idea categoricamente. È una cattiva idea SE degrada le prestazioni a qualsiasi livello problematico. –

risposta

7

Ci sono almeno due possibili incorporato modi per abbreviare il tuo codice:

si potrebbe usare Collection.addAll(Collection) che aggiunge ogni elemento della collezione passata come parametro al fine della raccolta .:

List<Looper> allLoopers = new ArrayList<Looper>(); 

... 

allLoopers.addAll(looperTracks); 
allLoopers.add(this); 

for(Looper looper : allLoopers) { 
    ... 
} 

oppure è possibile utilizzare un costruttore che prende una raccolta come parametro:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks); 

a causa del cambiamento di domanda: Tutti gli array può EA sily essere convertito in raccolte usando java.util.Arrays ad es.

List<Looper> someLooperTracks = Arrays.asList(looperTracks). 

Questo sarà avvolgere la matrice in un elenco dimensione fissa.

+0

Ho cambiato la domanda a causa di un errore da parte mia, ma la prima risposta funzionerà sicuramente. –

+0

Cool, grazie per aver raccolto il cambiamento nella domanda. L'ho appena realizzato: 'Lista allLoopers = new ArrayList (Arrays.asList (looperTracks));' –

+0

ed è possibile utilizzare il metodo nCopies() (vedere la mia risposta di seguito) – lorenzog

8

Si potrebbe almeno utilizzare il fatto che è possibile costruire una raccolta utilizzando un altro come valori di base. In base allo docs:

Costruisce una lista contenente gli elementi della raccolta specificata, nell'ordine in cui vengono restituiti dall'iteratore della raccolta. L'istanza ArrayList ha una capacità iniziale del 110% della dimensione della raccolta specificata.

Ciò significa che probabilmente ci sarà spazio per this senza dover ridimensionare.

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks); 
allLoopers.add(this); 

for (Looper looper : allLoopers) { 
    // Finally! I have a looper 
+0

+1, non sono sicuro di quanti secondi più veloce di me, ma buon lavoro! – ninesided

+0

Scusa scusa ho incasinato la domanda, LooperTracks è di tipo LooperTrack [] e LooperTrack implementa Looper. –

1

Perché non è possibile aggiungerli tutti come parte della chiamata del costruttore?

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks); 

allLoopers.add(this); 

for(Looper looper : allLoopers) { 
... 
} 
+0

Sì, questo ha funzionato con un po 'di modifiche. Grazie! –

1

A seconda di battitura, è possibile utilizzare:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks); 
allLoopers.add(this); 

o:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1); 
allLoopers.addAll(looperTracks); 
allLoopers.add(this); 
6

non credo che si può rendere più breve di questo ...

for (Looper looper : new ArrayList<Looper>(looperTracks){{ add(EnclosingClass.this); }}) { 
    // Finally! I have all loopers 
} 
+2

-1 Ogni volta che qualcuno posta questo hack, mi sento obbligato a chiamarlo come il terribile, brutto hack che è. E sei riuscito a lavorare in * due * delle caratteristiche del linguaggio più oscure: inizializzatori di istanze e riferimenti qualificati a 'this'! Buon lavoro che confonde tutti i tuoi colleghi. Inoltre, quanti lettori, anche se capisci questo, possono dirci in anticipo se "questo" verrà elaborato prima o dopo? Ho avuto un'ipotesi, ma mi sbagliavo, nonostante i miei 12 anni di esperienza Java a tempo pieno. Mi dispiace, ma terribile idea. –

+0

(Oltre a questo, * puoi * renderlo molto più breve di quello, se sei disposto ad usare le librerie.) –

+0

@Kevin Bourrillion, basta sapere che alle lingue dinamiche popolari, se riesci a ottenere tutto da solo linea, sei come il ragazzo cool in ufficio. Ma vero su questo codice. –

0

Puoi provare ad usare un immutable list usando t lui metodo nCopies(). Citando il riferimento API,

public static <T> List<T> nCopies(int n, T o)

restituisce un elenco immutabile costituito di n copie dell'oggetto specificato. L'oggetto dati appena assegnato è minuscolo (contiene un riferimento singolo all'oggetto dati). Questo metodo è utile in combinazione con il metodo List.addAll per generare elenchi. L'elenco restituito è serializzabile.

questo eviterà la prima foreach iterazione.

+0

Affascinante. Devo controllare questo. –

+0

Non capisco come questo aiuti. –

+0

@Kevin Bourrillion no. –

1

Nel caso in cui non si desideri utilizzare Groovy o JRuby a causa della loro natura dinamica, è consigliabile utilizzare Scala. Scala è tipizzato staticamente ma più conciso di Java.

+0

+1 perché è interessante sapere. Non pertinente per i miei scopi, ma interessante da sapere. –

2

Ho appena implementato un Iterator di Iterable s (è implementato in un modo più robusto testato// recensito da GuavaIterables.concat(Iterable...)):

// make a concatenation of iterables 
public static <T> Iterable<T> $(final Iterable<T> first, final Iterable<T>... iterables) { 
    List<Iterator<T>> allIterables = new LinkedList<Iterator<T>>(); 
    allIterables.add(first.iterator()); 

    for (Iterable<T> iterable : iterables) { 
     allIterables.add(iterable.iterator()); 
    } 

    final Iterator<Iterator<T>> iterators = allIterables.iterator(); 

    return new Iterable<T>() { 

     @Override 
     public Iterator<T> iterator() { 
      return new Iterator<T>() { 

       private Iterator<T> current = iterators.next(); 

       @Override 
       public boolean hasNext() { 
        if (current.hasNext()) { 
         return true; 
        } else { 
         if (iterators.hasNext()) { 
          current = iterators.next(); 
          return current.hasNext(); 
         } else { 
          return false; 
         } 
        } 
       } 

       @Override 
       public T next() { 
        return current.next(); 
       } 

       @Override 
       public void remove() { 
       } 
      }; 
     } 
    }; 
} 

usando il codice diventa:

for (Looper looper : $($(looperTracks), this)) { 

} 

nel caso in cui si cura l'implementazione è parte del mio Dollar library (rilesead come LGPL3).

+0

Interessante. Non sapevo che potevi usare il dollaro nei nomi dei metodi. Grazie, questo è un po 'quello che mi piacerebbe sapere. Librerie iso dinamiche per usare Java. –

+0

LGPL3 "contagioso" significa che tutto il codice che lo utilizza diventa automaticamente GPL? –

+0

Inoltre, ho modificato la domanda. Funzionerà se looperTracks è un array di tipo LooperTrack [] (implementa Looper)? –

1

È necessario assemblare tutto in un unico elenco? In caso contrario, cosa c'è di sbagliato in questo?

for (Looper looper : looperTracks) { 
    doSomething(looper); 
} 
doSomething(this); 
+0

Punto preso, ma il problema è che allora avrei bisogno di passare qualsiasi altra variabile nel metodo per fare Qualcosa. È sicuramente un'opzione (perché non ci sono altre variabili):) ... Grazie e +1 –

1

Prova

Looper[] loop = new Looper[looperTracks.length + 1]; 
System.arraycopy(looperTracks, 0, loop, 0, looperTracks.length); 
loop[looperTracks.length] = this; 
for (Looper l : loop) { ... } 

ma onestamente, perché non solo ciclo attraverso l'array esistente, e poi fare quello che vuoi a che fare con il ciclo per this dopo?

La List -version degli sguardi di cui sopra come:

List<Looper> loop = new ArrayList<Looper>(Arrays.asList(looperTracks)); 
loop.add(this); 
for (Looper l : loop) { ... } 
+0

Il motivo per cui non si vuole eseguire lo stesso codice due volte - loop e quindi fare qualsiasi cosa - è evitare di eseguire il lo stesso due volte. Farne un metodo è un altro modo di andare, dato che @Alan More sottolinea (sopra) –

+0

in un modo o nell'altro, si sta facendo la stessa cosa - incapsulando quello in un metodo o whathaveyou è una questione di leggibilità/manutenibilità (anzi questo l'intero esercizio di ottenerlo in un ciclo è), non la funzione. Dubito molto che la CPU veda qualcosa di diverso in entrambi i casi. – Carl

+0

@yar: In realtà, il mio suggerimento era esattamente lo stesso di @ Carl: itera attraverso la raccolta, quindi gestisci "questo" separatamente (non ho letto quella riga prima di postare la mia risposta). Il mio metodo 'doSomething()' era solo un segnaposto per qualunque cosa * stai * facendo con tutti quegli oggetti 'Looper'. –

4

Guava rende questo abbastanza facile:

for (Looper looper : ObjectArrays.concat(looperTracks, this)) {} 

Here è la documentazione per il metodo ObjectArrays#concat.

+1

Sì, non pensavo di cercare le librerie per fare questo genere di cose. Grandi cose! –

+0

E fino a quando Guava non rilasci qualcosa, puoi utilizzare Google Collections, che è un sottoinsieme di ciò che Guava diventerà, e di cui esiste già una versione 1.0: http://code.google.com/p/google-collections/ –

0

Ho intenzione di lanciarlo, ma non provare a ridurre il codice a scapito di renderlo leggibile.

Il codice leggibile è sempre il mio obiettivo quando inizio a scrivere il codice, semplicemente perché so che a un certo punto del futuro o io o qualcun altro lo vedremo e lo capiremo.

+0

è vero, ma allo stesso tempo, non si può ignorare la tendenza del corto-migliore (quindi Groovy, Ruby, Python). Detesto la brevità per mancanza di tempo - soprattutto l'idea tutto-su-una-linea - ma in questo caso è più breve IS più leggibile. –

Problemi correlati