Когда использовать функциональный интерфейс? (Java 8)
Недавно я перешел на разработку своего программного обеспечения для Java 8, и я постепенно улучшал свое использование Java 8 и становился все более комфортным с Java 8, и при этом я начал реализовывать все больше и больше функциональных интерфейсов, и в последнее время NetBeans Я начал предлагать заменить некоторые циклы for на функциональные интерфейсы, но из-за того, что программа работает, она выглядит намного медленнее, чем просто использование цикла for (1,9 с по сравнению с 0,9 с соответственно). Поэтому мой вопрос: стоит ли использовать функциональные интерфейсы вместо циклов for? Когда вообще следует использовать функциональные интерфейсы? Функциональные интерфейсы более эффективны в других отношениях? Заранее спасибо.
1 ответ
Если ваши лямбды не используют много переменных захвата, то я считаю, что производительность будет более сопоставима со стандартом для цикла. Преимущества использования лямбда-выражений заключаются в упрощении распараллеливания (хотя для упорядоченных потоков это может привести к снижению производительности) и упрощении синтаксиса для чтения. Также имейте в виду, что компилятор горячей точки со временем изменит результаты (ваше первое выполнение цикла, скорее всего, будет медленнее, чем последнее).
Я не знаю специфику, но в худшем случае, вы лямбда может быть реализован как анонимный класс. в лучшем случае это будет просто MethodHandle.
быстрый тест:
public class Test {
public static void main(String... args) {
Random r = new Random(42);
for(int i = 0; i < 10; i++) {
testFor();
testLambda();
}
}
protected static final int TestLength = 1024 * 1024 * 16;
protected static int result;
protected static void testFor() {
Random r = new Random(42);
long start = System.currentTimeMillis();
for(int i = 0; i < TestLength; i++) {
result = r.nextInt(TestLength);
}
long end = System.currentTimeMillis();
System.out.printf("testFor = %dms%n", end - start);
}
protected static void testLambda() {
Random r = new Random(42);
IntStream stream = IntStream.iterate(0, i -> r.nextInt(1024 * 1024));
long start = System.currentTimeMillis();
stream.limit(TestLength).forEach(i -> {result = i;});
long end = System.currentTimeMillis();
System.out.printf("testLambda = %dms%n", end - start);
}
}
результаты, достижения:
testFor = 209ms
testLambda = 207ms
testFor = 210ms
testLambda = 206ms
для параллельного потока результаты на самом деле медленнее (примерно в 2 раза на моей машине), потому что поток был упорядочен, и каждый поток имеет много накладных расходов на синхронизацию по сравнению с выполняемой работой (просто result = i
)