Введение
Критику языка программирования Java и программной платформы Java Язык программирования Java и программная платформа Java подверглись критике за выбор дизайна, включая реализацию генериков, принудительное объектно-ориентированное программирование, обработку неподписанных чисел, реализацию арифметики плавающей запятой и историю уязвимостей безопасности в основной реализации Java VM, HotSpot. Программное обеспечение, написанное на Java, особенно его ранние версии, подвергалось критике за его производительность по сравнению с программным обеспечением, написанным на других языках программирования. Разработчики также отметили, что различия в различных реализациях Java должны учитываться при написании сложных программ Java, которые должны работать со всеми из них.
The Java programming language and Java software platform have been criticized for design choices including the implementation of generics, forced object oriented programming, the handling of unsigned numbers, the implementation of floating point arithmetic, and a history of security vulnerabilities in the primary Java VM implementation, HotSpot. Software written in Java, especially its early versions, has been criticized for its performance compared to software written in other programming languages. Developers have also remarked that differences in various Java implementations must be taken into account when writing complex Java programs that must work with all of them.
Проверенные исключения
Java ввела проверенные исключения, где метод должен декларировать проверенные исключения, которые он бросает в подпись метода. Это может привести к излишне многословному коду. Ни один из основных языков не последовал примеру Java в реализации проверенных исключений.
Ориентация на существительные
По своей конструкции Java побуждает программистов думать о решении с точки зрения существительных (классов), взаимодействующих друг с другом, и думать о глаголах (методах) как об операциях, которые могут быть выполнены на этом существительном или с помощью этого существительного. Стив Йегге утверждает, что это вызывает ненужное ограничение экспрессивности языка, потому что класс может иметь несколько функций, которые работают на нем, но функция связана с классом и никогда не может работать на нескольких типах. Многие другие многопарадигматические языки поддерживают функции как конструкцию верхнего уровня. В сочетании с другими функциями, такими как перегрузка функций (одно глагола, несколько существительных) и общие функции (одно глагола, семейство существительных с определенными свойствами), программист может решить, решать ли конкретную проблему с точки зрения существительных или глаголов. Версия Java 8 представила некоторые функциональные функции программирования.
Типы неподписанных целых чисел
В Java отсутствуют типичные неподписанные целые числа. Неподписанные данные часто генерируются из программ, написанных на C, и отсутствие этих типов препятствует прямому обмену данными между C и Java. Неподписанные большие числа также используются в ряде областей численной обработки, включая криптографию, что может сделать Java более неудобным для использования для этих задач. Хотя можно обойти эту проблему, используя код конверсии и более крупные типы данных, это делает использование Java громоздким для обработки неподписанных данных. В то время как 32-битный подписанный целое число может быть использован для удержания 16-битного неподписанного значения без потерь, а 64-битный подписанный целое число - 32-битный неподписанный целое число, нет более крупного типа для удержания 64-битного неподписанного целое число. Во всех случаях потребляемая память может удвоиться, и обычно любая логика, основанная на переполнении комплемента двух, должна быть переписана. Если абстрагировать, вызовы функций становятся необходимыми для многих операций, которые являются родными для некоторых других языков. Альтернативно, можно использовать подписанные целые числа Java для эмуляции неподписанных целых чисел того же размера, но для этого требуется подробное знание битовых операций. Некоторая поддержка неподписанных целых типов была предоставлена в JDK 8, но не для неподписанных байтов и без поддержки в языке Java.
Перегрузка оператора
Java подвергается критике за то, что не поддерживает пользовательские операторы. Перегрузка оператора улучшает читабельность, поэтому его отсутствие может сделать код Java менее читабельным, особенно для классов, представляющих математические объекты, такие как сложные числа и матрицы. В Java есть только одно нецифровое использование оператора: + и += для цепочки струн. Однако это реализуется компилятором, который генерирует код для создания экземпляров StringBuilder. Невозможно создать пользовательские перегрузки оператора.
Типы сложных значений
В Java отсутствуют типы сложных значений, такие как structs в C, пакеты данных, которыми манипулируют непосредственно, а не косвенно через ссылки. Типы значений иногда бывают быстрее и меньше, чем классы с ссылками. Например, Java's HashMap реализуется как массив ссылок на HashMap. Объекты ввода, которые, в свою очередь, содержат ссылки на объекты ключа и значения. Поиск чего-то требует неэффективного двойного отсчета. Если бы Entry был типом значения, массив мог бы хранить пары ключевых значений напрямую, устраняя первую опосредованность, увеличивая локальность ссылки и уменьшая использование памяти и фрагментацию кучи. Кроме того, если Java поддерживает общие примитивные типы, ключи и значения могут храниться в массиве напрямую, удаляя оба уровня опосредованности.
Большие массивы
Java подвергается критике за то, что не поддерживает массивы из 231 (около 2,1 миллиарда) или более элементов. Это ограничение языка; спецификация языка Java, раздел 10.4, гласит, что: Массивы должны быть проиндексированы значениями int Попытка доступа к компоненту массива с длинным значением индекса приводит к ошибке времени компиляции. Поддержка больших массивов также потребует изменений в JVM. Это ограничение проявляется в таких областях, как коллекции, ограниченные 2 миллиардами элементов и невозможность отображения в памяти непрерывных сегментов файлов размером более 2 ГБ. Java также не имеет (за пределами своих 2D-массивов) многомерных массивов (последовательно выделенных одиночных блоков памяти, доступных с помощью одной опосредованности), что ограничивает производительность для научных и технических вычислений.
Arrays must be indexed by int values An attempt to access an array component with a long index value results in a compile time error. Supporting large arrays would also require changes to the JVM. This limitation manifests itself in areas such as collections being limited to 2 billion elements and the inability to memory map continuous file segments larger than 2 GB. Java also lacks (outside of its 2D arrays) multidimensional arrays (contiguously allocated single blocks of memory accessed by a single indirection), which limits performance for scientific and technical computing.
Интеграция примитивных и массивов
Средиземноморские и примитивные элементы являются несколько особенными и должны рассматриваться по-разному от классов. Это подвергалось критике, потому что требует много вариантов функций при создании библиотек общего назначения.
Параллелизм
Пер Бринч Хансен в 1999 году утверждал, что реализация параллелизма в Java в целом и мониторов в частности не обеспечивает гарантий и принудительных мер, необходимых для безопасного и надежного параллельного программирования. В то время как программист может установить дизайн и кодирование конвенций, компилятор не может предпринять никаких попыток их обеспечить, поэтому программист может невольно написать небезопасный или ненадежный код.
Сериализация
Java предоставляет механизм сериализации объектов, где объект может быть представлен как последовательность байтов, которая включает в себя поля данных, вместе с информацией о себе и его полях. После того, как объект сериализирован, он может быть позже десерализирован; то есть, информация типа и байты, которые представляют его данные, могут быть использованы для воссоздания объекта в памяти. Это создает очень серьезные теоретические и реальные риски для безопасности.
Арифметика с плавающей запятой
Хотя арифметика плавающей запятой Java в значительной степени основана на IEEE 754 (Стандарт для бинарной арифметики плавающей запятой), некоторые обязательные стандартные функции не поддерживаются даже при использовании модификатора strictfp, таких как флаги исключений и направленные округления. Расширенные типы точности, определенные IEEE 754 (и поддерживаемые многими процессорами), не поддерживаются Java.
Отсутствие тупулей
Java не поддерживает тупл, что приводит к распространению сторонних реализаций, которые должны быть импортированы и обработаны программистом.
Ламбда-выражения
До того как Java 8 представила выражения lambda, было трудно передать метод в качестве параметра другому методу.
Абстрактная связь между кодом и аппаратным обеспечением
В 2008 году Центр поддержки программных технологий Министерства обороны США опубликовал статью в "Журнале оборонной программной инженерии", в которой обсуждается непригодность Java в качестве первого языка обучения. Недостатком было то, что студенты "не чувствовали отношения между исходной программой и тем, что аппаратное обеспечение на самом деле будет делать" и невозможность "развить чувство стоимости времени выполнения написанного, потому что чрезвычайно трудно узнать, что в конечном итоге будет выполнено любым вызовом метода". В 2005 году Джоэл Спольски критиковал Java как слишком сосредоточенную часть учебных программ университетов в своем эссе "Опасности JavaSchools". Другие, как Нед Батчелдер, не согласны со Спольским за критику частей языка, которые ему было трудно понять, утверждая, что комментарий Спольского был скорее "субъективной речь".
Выступление
До 2000 года, когда HotSpot VM была реализована в Java 1.3, было много критики его производительности. Было показано, что Java работает со скоростью, сопоставимой с оптимизированным кодом, и современные JVM-реализации регулярно оцениваются как одна из самых быстрых языковых платформ, обычно не более чем в три раза медленнее, чем C и C++. Производительность существенно улучшилась с ранних версий. Производительность компиляторов JIT по сравнению с собственными компиляторами была показана в некоторых оптимизированных тестах. Байт-код Java может быть интерпретирован во время выполнения виртуальной машиной или компилирован во время загрузки или во время выполнения в коде, который работает непосредственно на аппаратном обеспечении компьютера. Интерпретация медленнее, чем нативное исполнение, но компиляция во время загрузки или во время выполнения имеет первоначальное наказание за производительность. Современные JVM-использования используют подход компиляции, поэтому после первоначального времени запуска производительность похожа на кода. В 2005 году разработчик игр и программист Джон Кармак (John D. Carmack) сказал о Java для мобильных телефонов: "Самая большая проблема в том, что Java очень медленна. На чистом уровне процессора / памяти / дисплея / связи, большинство современных сотовых телефонов должны быть значительно лучшими игровыми платформами, чем Game Boy Advance. С Java, на большинстве телефонов у вас остается мощность процессора оригинального ПК IBM 4,77 мГц (sic), и ужасный контроль над всем".
Безопасность
Платформа Java обеспечивает архитектуру безопасности, которая предназначена для того, чтобы позволить пользователю запускать ненадежный байт-код в "песочнице" для защиты от вредоносного или плохо написанного программного обеспечения. Эта функция "sandboxing" предназначена для защиты пользователя путем ограничения доступа к функциям платформы и API, которые могут быть использованы вредоносными программами, такими как доступ к локальной файловой системе или сети или выполнение произвольных команд. В 2010 году произошло значительное увеличение числа вредоносных программ, нацеленных на недостатки безопасности в механизмах песочницы, используемых в реализациях Java, включая Oracle. Эти недостатки позволяют ненадежному коду обходить ограничения песочницы, подвергая пользователя атакам. Врачи были исправлены обновлениями безопасности, но все еще использовались на машинах без обновлений. Критики предполагают, что пользователи не обновляют свои установки Java, потому что они не знают, что они их имеют, или как их обновлять. Многие организации ограничивают установку программного обеспечения пользователями, но медленно развертывают обновления. Oracle подвергается критике за то, что не оперативно предоставляет обновления для известных ошибок безопасности. Когда Oracle наконец выпустил патч для широко используемых недостатков в Java 7, он удалил Java 6 с машин пользователей, несмотря на то, что он широко используется корпоративными приложениями, на которые Oracle заявил, что они не подвержены воздействию недостатков. В 2007 году исследовательская группа во главе с Марко Пистоией выявила еще один важный недостаток модели безопасности Java, основанный на инспектировании стека. Когда доступ к чувствительному к безопасности ресурсу, менеджер безопасности запускает код, который проходит по стеку вызовов, чтобы убедиться, что база кода каждого метода имеет право доступа к ресурсу. Это делается для предотвращения запутанных атак на помощников, которые происходят каждый раз, когда законная, более привилегированная программа обманывается другой, чтобы злоупотребить своей властью. Проблема с заместителем, который запутался, - это особый тип эскалации привилегий. Пистоя отметил, что когда доступ к чувствительному к безопасности ресурсу, код, ответственный за получение ресурса, может больше не находиться в стеке. Например, метод, выполненный в прошлом, может изменить значение поля объекта, которое определяет, какой ресурс использовать. Этот вызов метода может больше не быть в стеке, когда он проверяется. Некоторые разрешения имплицитно эквивалентны AllPermission Java. К ним относятся разрешение на изменение текущего менеджера безопасности (и замену его на тот, который потенциально может обойти инспекцию стека), разрешение на создание экземпляра и использование загрузчика пользовательского класса (который может выбрать ассоциировать AllPermission с вредоносным классом при его загрузке) и разрешение на создание пользовательского разрешения (которое может объявить себя столь же мощным, как AllPermission через его метод подразумевает). Эти проблемы задокументированы в двух книгах Пистои о безопасности Java.
Параллельные установки
До Java 7 установщики не удаляли старые установки Java. На Windows-системах было обычным видеть несколько установок Java на одном компьютере. Разрешалось несколько установок и их могли использовать программы, которые полагаются на определенные версии, включая вредоносные программы. Эта проблема была решена в Java 7: с разрешения пользователя, установщик удаляет более ранние установки.
Автоматические обновления
С 2014 года общие сторонние инструменты (такие как Adobe Flash и Adobe Reader) были предметом тщательного изучения уязвимостей безопасности. Adobe и другие перешли на автоматические обновления в Windows. Они не требуют никаких действий пользователя и гарантируют, что проблемы безопасности оперативно решаются с минимальными усилиями пользователей или администраторов. По состоянию на 2015 год, Java 8 все еще требует от пользователей обновлять Java сами. Но в Windows только те, кто имеет права администратора, могут обновлять программное обеспечение. Обновляющий Windows Java часто запускает нарушительный запрос на повышение уровня пользовательского учетного счета: что бы пользователи ни выбрали, они все равно получают одно и то же сообщение "Java needs to be updated".
Проблемы безопасности и возможные эксплойты, связанные с JIT
Компиляция JIT в основном использует исполняемые данные, и, таким образом, создает проблемы безопасности и возможные эксплойты.