2016-04-08 6 views
17

posso fare la conversione con codice come questo:convertire un oggetto [] di booleani per un valore booleano [] utilizzando flussi

Object[] array = (Object[]) message.get(key); 
boolean[] result = new boolean[array.length]; 
for (int i = 0; i < array.length; i++) { 
    result[i] = (boolean) array[i]; 
} 

Ma, ero pensare che è possibile fare la stessa conversione utilizzando Java 8 flussi. Inizio a codificare qualcosa del genere:

boolean[] = Arrays.stream(array) 
        .map(Boolean.class::cast) 
        .map(Boolean::booleanValue) 
        .toArray() 

Ma questo codice non funziona. Compilatore dice

incompatible types: java.lang.Object[] cannot be converted to boolean[] 

Sto cercando di capire qual è il problema con il codice. Penso che map(Boolean::booleanValue) restituirebbe un flusso di valori booleani che posso raccogliere con toArray.

+2

Questo non funzionerà perché 'Object []' e 'boolean []' sono tipi in Java che non sono convertibili, quindi in realtà 'Object [] = boolean []' non funzionerà neanche. – Jagger

+2

'.toArray()' qui è generico, quindi 'Object []' è il meglio che puoi ottenere. Puoi scrivere il tuo raccoglitore per restituire 'booleano []'. –

+0

@SashaSalauyou È tuttavia possibile utilizzare 'toArray (IntFunction generator)' per restituire un array tipizzato. Ho aggiunto una risposta come esempio. –

risposta

15

No, perché map(Boolean::booleanValue) espande a

map((Boolean value) -> (Boolean)value.booleanValue()); 

(nota la autoboxing inserito dal compilatore, perché la funzione passata a map() deve restituire un Object, non un boolean)

questo motivo la Gli stream Java8 includono un sacco di classi specializzate (IntStream, LongStream e DoubleStream). Purtroppo, non esiste una classe di stream specializzata per boolean.

8

Se non sei contrario all'idea di avere una lista, invece, si può semplicemente eseguire collect come la vostra azione terminale:

final List<Boolean> boolList = Arrays.stream(array) 
            .map(Boolean.class::cast) 
            .map(Boolean::booleanValue) 
            .collect(Collectors.toList()); 

Il flusso come definito qui è solo in grado di produrre un Object[] se tenta di raccoglierlo in un array. L'utilizzo di un elenco consentirà almeno di mantenere il tipo in cui si desidera convertirlo.

+0

Solo per curiosità, l'OP non può convertire la lista in un array booleano in seguito se lo volesse davvero? –

+2

@JeelShah: Sì, ma sarebbero in grado di ottenere un 'Boolean []', non un 'booleano []'. Se l'OP voleva il 'booleano []' avrebbero dovuto fare un po 'più di lavoro. – Makoto

+0

Ahhh okay. Grazie per le informazioni aggiuntive! –

4

Penso che valga anche la pena notare che esiste uno toArray(IntFunction<A[]> generator) che ti permetterà almeno di avere un risultato finale di Boolean[] che è più vicino a quello che volevi.

Boolean[] boolArray = Arrays.stream(array) 
       .map(Boolean.class::cast) 
       .map(Boolean::booleanValue) 
       .toArray(Boolean[]::new); 
5

Gli unici flussi di tipo primitivo sono IntStream, LongStream e DoubleStream. In particolare, non esiste lo BooleanStream e non esiste un modo idiomatico per convertire uno Stream<Boolean> in uno boolean[].

Se avete bisogno di questa funzionalità di frequente è possibile utilizzare una classe di utilità come questo:

public final class BooleanUtils { 

    private BooleanUtils() {} 

    public static boolean[] listToArray(List<Boolean> list) { 
     int length = list.size(); 
     boolean[] arr = new boolean[length]; 
     for (int i = 0; i < length; i++) 
      arr[i] = list.get(i); 
     return arr; 
    } 

    public static final Collector<Boolean, ?, boolean[]> TO_BOOLEAN_ARRAY 
     = Collectors.collectingAndThen(Collectors.toList(), BooleanUtils::listToArray); 
} 

Poi, dato un Stream<Boolean>, si sarà in grado di fare:

boolean[] arr = stream.collect(BooleanUtils.TO_BOOLEAN_ARRAY); 
2

Java i tipi primitivi aren 't tipi di riferimento, quindi non è possibile convertire direttamente Boolean in boolean (autoboxing and unboxing sono stati aggiunti alla lingua in Java 1.5 e non funzionano con matrici di tipi di wrapper per i tipi primitivi).Tuttavia, si potrebbe usare un IntStream.range(int, int) come

boolean[] result = new boolean[array.length]; 
IntStream.range(0, array.length).forEach(x -> result[x] = (boolean) array[x]); 
2

Nel mio libero StreamEx biblioteca c'è un collettore toBooleanArray che crea un primitivo matrice booleana:

boolean[] result = Arrays.stream(array) 
         .collect(MoreCollectors.toBooleanArray(obj -> (boolean)obj)); 

Se non vi piace utilizzando la libreria di terze parti si può implementare questo collettore da solo:

public static <T> Collector<T, ?, boolean[]> toBooleanArray(Predicate<? super T> predicate) { 
    class Acc { 
     BitSet bs = new BitSet(); 
     int count = 0; 
    } 
    return Collector.of(Acc::new, (acc, t) -> acc.bs.set(acc.count++, predicate.test(t)), 
      (acc1, acc2) -> { 
       acc2.bs.stream().forEach(i -> acc1.bs.set(i + acc1.count)); 
       acc1.count += acc2.count; 
       return acc1; 
      }, acc -> { 
       boolean[] res = new boolean[acc.count]; 
       acc.bs.stream().forEach(i -> res[i] = true); 
       return res; 
      }); 
} 

Funziona bene per flussi sequenziali e paralleli e uscire e memoria-friendly.

Problemi correlati