Эккель Брюс
Шрифт:
*/// ~
Цикл while генерирует случайные значения как искомые до тех пор, пока одно из них не будет найдено в массиве.
Если искомое значение найдено, метод Arrays.binarySearchQ возвращает неотрицательный результат. В противном случае возвращается отрицательное значение, представляющее позицию элемента при вставке (при сохранении сортировки массива). Если массив содержит повторяющиеся значения, алгоритм поиска не дает гарантий относительно того, какой именно из дубликатов будет обнаружен. Алгоритм проектировался не для поддержки дубликатов, а для того, чтобы переносить их присутствие. Если вам нужен отсортированный список без повторений элементов, используйте TreeSet (для сохранения порядка сортировки) или LinkedHashSet (для сохранения порядка вставки). Эти классы автоматически берут на себя все детали. Только в ситуациях, критичных по быстродействию, эти классы заменяются массивами с ручным выполнением операций.
При сортировке объектных массивов с использованием Comparator (примитивные массивы не позволяют выполнять сортировку с Comparator) необходимо включать тот же объект Comparator, что и при использовании binarySearch (перегруженной версии). Например, программу StringSorting.java можно модифицировать для выполнения поиска:
//• arrays/AlphabeticSearch.java // Поиск с Comparator, import java.util.*; import net.mindview.util.*;
public class AlphabeticSearch {
public static void main(String[] args) {
String[] sa = Generated.array(new String[30],
new RandomGenerator String(5)); Arrays.sort(sa. String.CASE_INSENSITIVE_ORDER); System.out.pri ntln(Arrays.toStri ng(sa)); int index = Arrays.binarySearch(sa. sa[10],
Stri ng. CASE JNSENSITI VE_0RDER); System.out.printlпС'Индекс: "+ index + "\n"+ sa[index]);
}
} /* Output
[bklna. cQrGs. cXZJo. dLsmw. eGZMm. EqUCB. gwsqP. hKcxr, HLGEa. HqXum, HxxHv, JMRoE. JmzMs. Mesbt, MNvqe, nyGcF, ogoYW, OneOE. OWZnT. RFJQA. rUkZP. sgqia, slJrL, suEcU. uTpnX, vpfFv, WHkjU. xxEAJ, YNzbr, zDyCy] Индекс 10 HxxHv *///.-
Объект Comparator передается перегруженному методу binarySearch в третьем аргументе. В приведенном примере успех поиска гарантирован, так как искомое значение выбирается из самого массива.
Резюме
В этой главе вы убедились в том, что язык Java предоставляет неплохую поддержку низкоуровневых массивов фиксированного размера. Такие массивы отдают предпочтение производительности перед гибкостью. В исходной версии Java низкоуровневые массивы фиксированного размера были абсолютно необходимы — не только потому, что проектировщики Java решили включить в язык примитивные типы (также по соображениям быстродействия), но и потому, что поддержка контейнеров в этой версии была крайне ограниченной.
В последующих версиях Java поддержка контейнеров была значительно улучшена. Сейчас контейнеры превосходят массивы во всех отношениях, кроме быстродействия, хотя производительность контейнеров была значительно улучшена. С добавлением автоматической упаковки и параметризации хранение примитивов в контейнерах требует меньших усилий и способствует дальнейшему переходу с низкоуровневых массивов на контейнеры. Так как параметризация открыла доступ к типизованным контейнерам, в этом отношении массивы тоже утратили исходные преимущества.
Как было показано в этой главе, параметризация плохо сочетается с контейнерами. Даже если вам удастся тем или иным способом заставить их работать вместе, во время компиляции вы будете получать предупреждения.
Все эти факторы показывают, что при программировании для последних версий Java следует отдавать предпочтение контейнерам перед массивами. На массивы следует переходить только при критичных требованиях по быстродействию — и только в том случае, если переход принесет ощутимую пользу.
Система
ввода/вывода
Java
Создание хорошей системы ввода/вывода является одной из труднейших задач разработчика языка. Доказательством этого утверждения служит множество подходов, используемых при разработке систем ввода/вывода.
Основная сложность состоит в том, что необходимо учесть все возможные ситуации. Это не только наличие множества источников и приемников данных, с которыми необходимо поддерживать связь (файлы, консоль, сетевые соединения), но и реализации различных форм этой связи (последовательный доступ, произвольный, буферизованный, двоичный, символьный, построчный, пословный и т. д.).
Разработчики библиотеки Java решили начать с создания огромного количества классов. Вообще говоря, в библиотеке ввода/вывода Java так много классов, что потеряться в них проще простого (парадоксально, но сама система ввода/вывода Java в действительности не нуждается в таком количестве классов). Потом, после выхода первой версии языка Java, в библиотеке ввода/вывода последовали значительные изменения: к ориентированным на посылку и прием байтов классам добавились основанные на Юникод классы, работающие с символами. В JDK 1.4 классы nio (от сочетания «new I/O», «новый ввод/вывод») призваны улучшить производительность и функциональность. В результате, чтобы понять общую картину ввода/вывода в Java и начать использовать ее, вам придется изучить порядочный ворох классов. Вдобавок не менее важно понять и изучить эволюцию библиотеки ввода/вывода, несмотря на вашу очевидную реакцию: «Избавьте меня от истории! Просто покажите, как работать с библиотекой!» Если не уяснить причины изменений, проведенных в библиотеке ввода/вывода, вскоре мы запутаемся в ней и не сможем твердо аргументировать сделанный нами выбор в пользу того или иного класса.