Производительность функции split

В одном из проектов в очередной раз пришлось писать собственную реализацию split строки, в связи с этим заинтересовался о производительности различных решений.

Для тестирования выбраны следующие кандидаты:

  • JDK
  • Guava
  • Apache commons-lang
  • Custom

Проводилось тестирование следующих параметров в различных комбинациях: короткая строка большое количество итераций, длинная строка малое количество итераций.

Поскольку Guava поддерживает lazy вычисление, то была добавлена ещё одна комбинация: отложенная итерация по результатам и непосредственная итерация.

В результате получились следующие значения:

Выводы:

  • Стабильно плохой результат показывает Pattern.split. Он генерирует множество объектов, да и слишком общий для решения такой частной задачи. Использования паттерна это достаточно большой overhead.
  • для не lazy тестов google guava показывает достаточно плохой результат. Видимо это связано с количеством мусора который генерирует библиотека. В исходных кодах можно найти следующие конструкции:
String description = new StringBuilder("CharMatcher.is(")  
    .append(Integer.toHexString(match))  
    .append(")")  
    .toString();  
return new CharMatcher(description) {...}; 
  • Заметное отставание даёт commons-lang на lazy итерациях. Наверное потому, что они не поддерживаются.
  • Как всегда, победителем становится собственная реализация.

Выводы 2:

Как говорят в google guava: “Знайте свои библиотеки”. Даже знаменитые библиотеки иногда могут быть написаны очень коряво. В частности в guava лежат очень много здравых идей, например, “везде возвращать Iterable” для lazy обхода. Это очень мощная идея, о которой я раньше не догадывался. Однако реализация очень сильно страдает от большого количество “как-бы” функционального кода, который в java сильно ударяет по производительности.