Подтвердить что ты не робот

Java-эквивалент С# 'Enumerable.Any'

В С# существует способ уменьшить длину if-оператора, используя Enumerable.Any, чтобы проверить, удовлетворяют ли элементы в последовательности условию (https://msdn.microsoft.com/en-us/library/vstudio/bb534972%28v=vs.100%29.aspx).

Например, вместо:

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

Мы можем использовать

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

Есть ли эквивалентный, если не лучше, способ сделать это в Java?

4b9b3361

Ответ 1

С Java 8 вы можете написать что-то вроде:

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

Из любопытства я провел тест, чтобы сравнить этот метод с регулярным выражением. Код и результаты ниже (более низкий балл = быстрее). Потоки выполняются на порядок лучше, чем регулярное выражение.

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

код:

@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).*$");
  }
}

Ответ 2

С Java 8 это возможно с помощью метода anyMatch:

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

}

Ответ 4

Если у вас нет Java 8, вы можете просто использовать регулярное выражение для выполнения своей задачи.

string.matches("^.*?(<|>|p|1|&).*$") должен сделать трюк.

EDIT:

Интересно, какое решение работает быстрее. Несмотря на то, что JIT может встроить всю добротность лямбды, Stream (s) может быть медленнее, чем использование регулярного выражения. Я мог бы быть совершенно неправ, и я был бы признателен за понимание этой проблемы с Java 8 stalwarts.