Почему list.size ()> 0 медленнее, чем list.isEmpty () в Java?

Быстрое гугление дает: http://msdn.microsoft.com/en-us/library/bb385193.aspx

48
задан Joachim Sauer 2 October 2009 в 02:10
поделиться

8 ответов

Ваш тестовый код ошибочен.

Просто измените порядок, т.е. сначала вызовите isEmpty и размер> 0 секунд, и вы получите противоположный результат . Это происходит из-за загрузки класса, кеширования и т. Д.

56
ответ дан 7 November 2019 в 12:03
поделиться

Для ArrayList , да - вы правы, что операции занимают (примерно) одинаковое время.

Для других реализаций List - например, наивный связанный список * - подсчет размера может занять очень много времени, в то время как вы на самом деле заботитесь только о том, больше ли он нуля.

Итак, если вы абсолютно уверены, что список является реализацией ArrayList и никогда не изменится, тогда это на самом деле не имеет значения; но:

  1. Это плохая практика программирования, чтобы привязывать себя к конкретной реализации.
  2. Если что-то изменится через несколько лет после реструктуризации кода, тестирование покажет, что «это работает», но все работает менее эффективно чем раньше.
  3. Даже в лучшем случае, size () == 0 по-прежнему не быстрее , чем isEmpty () , поэтому нет веских причин использовать первое.
  4. isEmpty ( ) - это более четкое определение того, что вас действительно волнует и что вы тестируете, что делает ваш код более понятным.

* Первоначально я написал здесь LinkedList, неявно ссылаясь на java.util. LinkedList , хотя эта конкретная реализация явно сохраняет его размер, делая здесь size () операцией O (1). Наивная операция связанного списка может этого не сделать, и в более общем смысле нет гарантии эффективности для реализаций List .

83
ответ дан 7 November 2019 в 12:03
поделиться

Извините, но ваш тест неверен. Взгляните на Теория и практика Java: Анатомия некорректного микробенча , чтобы получить общее описание того, как подходить к тестам.


Обновление : для правильного теста вам следует изучить Japex .

15
ответ дан 7 November 2019 в 12:03
поделиться

Вы сказали:

Здесь eTime-sTime> eeTime-eTime во всех случаях Почему?

Во-первых, вероятно, это из-за вашего тестового кода. Вы не можете проверить скорость вызова l.size () и l.isEmpty () одновременно, поскольку они оба запрашивают одно и то же значение. Скорее всего, вызов l.size () загрузил размер вашего списка в кеш процессора, и в результате вызов l.isEmpty () стал намного быстрее.

Вы можете попробовать вызвать l.size () пару миллионов times и l.isEmpty () пару миллионов раз в двух отдельных программах , но теоретически компилятор может просто оптимизировать все эти вызовы, так как на самом деле вы ничего не делаете с результатами.

В в любом случае разница в производительности между ними будет незначительной, особенно после того, как вы выполните сравнение, которое вам нужно сделать, чтобы увидеть, пуст ли список ( l.size () == 0 ). Скорее всего, сгенерированный код будет почти полностью похож. Как отмечали некоторые другие авторы, в этом случае вы хотите оптимизировать для удобочитаемости, а не для скорости.

edit: Я тестировал это сам. Это в значительной степени жеребьевка. size () и isEmpty () , использованные в Vector , дали разные результаты на длинных прогонах, ни один из них не побеждал друг друга. При запуске на ArrayList size () казался быстрее, но ненамного. Скорее всего, это связано с тем, что доступ к вектору синхронизирован, поэтому при тестировании доступа к этим методам вы действительно видите накладные расходы на синхронизацию, которые могут быть очень чувствительными.

Здесь следует отметить, что когда вы пытаетесь оптимизировать вызов метода с разницей во времени выполнения на пару наносекунд, вы делаете это неправильно . Сначала разберитесь с основами, например, используя Long s, где вы должны использовать long .

5
ответ дан 7 November 2019 в 12:03
поделиться

Учитывая эти две реализации, скорость должна быть одинаковой, это верно.

Но это далеко не единственные возможные реализации этих методов. Например, примитивный связанный список (тот, который не хранит размер отдельно) может ответить isEmpty () намного быстрее, чем вызов size () .

Что еще более важно: isEmpty () точно описывает ваше намерение, в то время как size () == 0 является излишне сложным (конечно, не очень сложным, но следует избегать любой ненужной сложности).

2
ответ дан 7 November 2019 в 12:03
поделиться

В целом невозможно сказать, что быстрее, потому что это зависит от того, какую реализацию интерфейса List вы используете.

Предположим, мы говорим о ] ArrayList . Найдите исходный код ArrayList , вы можете найти его в файле src.zip в каталоге установки JDK.

0
ответ дан 7 November 2019 в 12:03
поделиться

Подсчет элементов в связанном списке может быть очень медленным.

1
ответ дан 7 November 2019 в 12:03
поделиться

Согласно PMD (анализатор исходного кода Java на основе статического набора правил) isEmpty () является предпочтительным. Здесь вы можете найти набор правил PMD. Найдите правило «UseCollectionIsEmpty».

http://pmd.sourceforge.net/rules/design.html

По мне, это также помогает поддерживать согласованность всего исходного кода, а не половине людей, использующих isEmpty ( ), а остальные - с помощью size () == 0.

1
ответ дан 7 November 2019 в 12:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: