2015-06-19 13 views
24

In C# esiste un modo per ridurre la lunghezza di un'istruzione if utilizzando Enumerable.Any per verificare se gli elementi in una sequenza soddisfano una condizione (https://msdn.microsoft.com/en-us/library/vstudio/bb534972%28v=vs.100%29.aspx).Equivalente Java di C# 'Enumerable.Any'

Per esempio, invece di:

If (string.Contains(">") || string.Contains("<") || string.Contains("&") || string.Contains("l") || string.Contains("p")) 

Possiamo usare

if (new [] { ">", "<", "&", "l", "p"}.Any(w => string.Contains(w))) 

Esiste un equivalente, se non migliore, modo di fare questo in Java?

+1

Solo per completezza: è anche possibile utilizzare '.Any (string.Contains)' piuttosto che il più dettagliato '.Any (w => string.Contains (w))' in C#. – Bob

risposta

23

Con Java 8 è possibile scrivere qualcosa di simile:

if (Stream.of(">", "<", "&", "l", "p").anyMatch(string::contains)) { 
    ... 
} 

Per curiosità mi sono imbattuto un punto di riferimento per confrontare questo metodo vs un'espressione regolare. Codice e risultati di seguito (punteggio inferiore = più veloce). Gli stream hanno un ordine di grandezza migliore della regex.

Benchmark         (s) Mode Samples  Score Error Units 
c.a.p.SO30940682.stream >aaaaaaaaaaaaaaaaaaaaa avgt  10 49.942 ± 1.936 ns/op 
c.a.p.SO30940682.stream aaaaaaaaaaaaaaaaaaaaa> avgt  10 54.263 ± 1.927 ns/op 
c.a.p.SO30940682.stream aaaaaaaaaaaaaaaaaaaaap avgt  10 131.537 ± 4.908 ns/op 
c.a.p.SO30940682.stream paaaaaaaaaaaaaaaaaaaaa avgt  10 129.528 ± 7.352 ns/op 
c.a.p.SO30940682.regex >aaaaaaaaaaaaaaaaaaaaa avgt  10 649.867 ± 27.142 ns/op 
c.a.p.SO30940682.regex aaaaaaaaaaaaaaaaaaaaa> avgt  10 1047.122 ± 89.230 ns/op 
c.a.p.SO30940682.regex aaaaaaaaaaaaaaaaaaaaap avgt  10 1029.710 ± 61.055 ns/op 
c.a.p.SO30940682.regex paaaaaaaaaaaaaaaaaaaaa avgt  10 694.309 ± 32.675 ns/op 

Codice:

@State(Scope.Benchmark) 
@BenchmarkMode(Mode.AverageTime) 
public class SO30940682 { 

    @Param({">aaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaa>", 
      "aaaaaaaaaaaaaaaaaaaaap", "paaaaaaaaaaaaaaaaaaaaa"}) String s; 

    @Benchmark public boolean stream() { 
    return Stream.of(">", "<", "&", "l", "p").anyMatch(s::contains); 
    } 

    @Benchmark public boolean regex() { 
    return s.matches("^.*?(>|<|&|l|p).*$"); 
    } 
} 
+0

@MarcoAcierno String :: contiene il riferimento a un metodo statico, che non esiste. https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html – Ezequiel

+2

Il mio male, ho rimosso il commento. Ho perso il fatto che 'stringa' è una variabile –

+0

Grazie per aver chiarito. Mi chiedo se Regex sarebbe più veloce per il controllo delle sottostringhe invece dei singoli caratteri. Non sono sicuro che 'contains()' funzioni bene in questi casi. –

9

con Java 8, questo è possibile con il metodo anyMatch:

if (Stream.of(">", "<", "&", "l", "p").anyMatch(w -> string.contains(w))) { 

} 
6

Se non si dispone di Java 8, si potrebbe utilizzare un normale espressione per realizzare il tuo compito.

string.matches("^.*?(<|>|p|1|&).*$") dovrebbe fare il trucco.

EDIT:

Mi chiedo quale sia la soluzione esegue più veloce. Anche se JIT è in grado di allineare tutta la qualità lambda, Stream (s) potrebbe essere più lento rispetto all'utilizzo di un'espressione regolare. Potrei sbagliarmi completamente e apprezzerei qualsiasi intuizione su questo dai sostenitori di Java 8.

+0

Grazie! Questo funziona perfettamente. – Mirodinho

+1

@ Amrito10, in qualsiasi momento! –