Когда я перебираю коллекцию, используя новый синтаксический сахар Java 8, такой как
myStream.forEach(item -> {
// do something useful
});
Разве это не эквивалентно приведенному ниже фрагменту "старого синтаксиса"?
myStream.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
// do something useful
}
});
Означает ли это, что новый анонимный Consumer
объект создается в куче каждый раз, когда я перебираю коллекцию? Сколько места в куче для этого требуется? Какие последствия для производительности это имеет? Означает ли это, что при итерации по большим многоуровневым структурам данных мне лучше использовать старый стиль циклов?
Ответы:
Это эквивалентно, но не идентично. Проще говоря, если лямбда-выражение не захватывает значения, это будет синглтон, который повторно используется при каждом вызове.
Поведение точно не указано. JVM предоставляется большая свобода в том, как ее реализовать. В настоящее время JVM Oracle создает (по крайней мере) один экземпляр для каждого лямбда-выражения (т.е. не разделяет экземпляр между разными идентичными выражениями), но создает одиночные экземпляры для всех выражений, которые не захватывают значения.
Вы можете прочитать этот ответ для получения более подробной информации. Там я не только дал более подробное описание, но и протестировал код для наблюдения за текущим поведением.
Это описано в Спецификации языка Java®, глава « 15.27.4. Оценка лямбда-выражений во время выполнения »
Вкратце:
источник
Создание экземпляра, представляющего лямбду, сильно зависит от точного содержимого тела лямбды. А именно, ключевым фактором является то, что лямбда захватывает из лексической среды. Если он не фиксирует какое-либо состояние, которое изменяется от создания к созданию, то экземпляр не будет создаваться каждый раз при входе в цикл for-each. Вместо этого синтетический метод будет сгенерирован во время компиляции, и сайт использования лямбда просто получит одноэлементный объект, который делегирует этому методу.
Также обратите внимание, что этот аспект зависит от реализации, и вы можете ожидать будущих улучшений и улучшений HotSpot для повышения эффективности. Есть общие планы, например, сделать легкий объект без полного соответствующего класса, который имеет достаточно информации для передачи в единственный метод.
Вот хорошая и доступная подробная статья по этой теме:
http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
источник
Вы передаете
forEach
методу новый экземпляр . Каждый раз, когда вы это делаете, вы создаете новый объект, но не по одному для каждой итерации цикла. Итерация выполняется внутриforEach
метода с использованием того же экземпляра объекта «обратного вызова», пока она не будет выполнена в цикле.Таким образом, память, используемая циклом, не зависит от размера коллекции.
Да. У него есть небольшие отличия на очень низком уровне, но я не думаю, что вам следует о них беспокоиться. В выражениях Lamba вместо анонимных классов используется функция invokedynamic.
источник