Плохая Java или как не надо делать

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

    HashSet

    Не знаю почему было принято такое решение, но HashSet реализован на HashMap, да — сэкономили время на создание, но это же одна из основных коллекций, почему к ее созданию не подошли более ответственно — не понятно. Всё-таки, можно было создать HashSet более оптимально. HashMap несет излишнюю архитектуру в контексте задач HashSet. Например, внутри HashSet есть следующий код:
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    

    Это значит, что любое ваше значение внутри HashSet будет ассоциироваться со ссылкой на этот обьект. Это тоже самое, что:
    Map.put(key, PRESENT);
    

    Казалось бы, подумаешь — 8 байт, который будут использоваться всеми. Но не забывайте что при каждой вставке в HashSet, создается Map.Entry, в котором 4 ссылки (еще 16 лишних байт на каждый элемент). Расточительно, не находите? Почему так? Большая загадка… Спасибо хоть не унаследовались.

    Default logger

    Кто в проекте не использует log4j? А можете сходу назвать библиотеки, которые тоже обходятся без него? Думаю это трудные вопросы. Понимаю, java не может подстраиваться под каждую конкретную задачу, но добавили же стандартный Logger, так почему за 10 лет существования log4j, java так и не взяла лучшее из него? Представьте на сколько бы уменьшились все приложения, особенно сложные, где в конечной сборке может оказаться несколько разных версий логера.

    Clonable

    Все знают что интерфейс Clonable пустой, без единого метода и переменной, просто маркер для JVM. Вопрос — почему? Ведь, если наследоваться от него, то мы пытаемся определить некое поведение и следуя парадигмам ООП он должен содержать метод clone(), который и определял бы это самое поведение. Безусловно, иногда очень удобно без переопределения clone получить копию обьекта. Тем не менее, переопределять этот метод, по сути, приходится во всех классах у которых есть хотя бы одна коллекция обьектов модели, чтобы получить полную копию, а не просто ссылки на те же обьекты внутри коллекции. Я не знаю почему разработчики не определили в этом интерфейсе ни одного метода. Надеюсь у них была на это причина, хотя, наверное, просто забыли. Как следствие — метод clone() в Object.

    Serializable

    Ситуация аналогична Clonable, но тут по крайней мере можно возразить — в большинстве случаев
    мы не определяем поведение вручную, а полагаемся на стандартную реализацию и было бы очень не удобно постоянно переопределять какие-то методы сериализации + постоянно следить за добавлением новых полей, добавлять их в методы. Ну и специально для этих целей есть Externalizable. Тем не менее, мы знаем, что можно изменить стандартное поведение сериализации предопределив writeObject() и readObject(). Как-то не по ООПшному.

    Properties

    Все мы так или иначе работаем с классом Properties. Открываем исходники и что мы видим?
    class Properties extends Hashtable<Object,Object>
    

    Зачем? Любой знает, что композиция лучше наследования, особенно, если это наследование не имеет логического смысла и не упрощает модель приложения. А методы load(InputStream inStream) и load0(LineReader lr)? А как же перегрузка методов? То же самое и со store0(), хорошо хоть внутри класса спрятаны. Кстати, такие методы встречаются повсеместно в core java, похоже на чей-то стиль.

    Классы оболочки примитивных типов

    Классы-оболочки — избыточны, гораздо удобней было бы оперировать примитивами и иметь возможность присваивать им null значение. Если простой int занимает 4 байта, то обьект Integer уже целых 16. Постоянное приведение, сравнение по equals. Зачем все это? Дальше:
    Boolean.getBoolean();
    Long.getLong();
    Integer.getInteger()
    

    Загадочные методы. До сих пор не могу понять какую роль они должны выполнять и почему методы которые
    проверяют System.getProperty() находятся в классах оболочка, а не в классе Properties.

    switch

    Конечно же, каждый java разработчик знает, что оператор switch работает только с целым типом, а начиная в 7-й java и со строками. Но к чему эти ограничения? Судя по реализации switch в 7-й версии — он работает со строкой исходя из hashСode() и equals(). Тогда вопрос — почему только строки? Легко можно было реализовать оператор для любого обьекта, но почему-то этого не было сделано. Очередная загадка.

    Collections

    В List и Set есть прекрасный метод retainAll() — пересечение множеств, но почему-то нету метода для разницы множеств. Конечно, его легко можно реализовать самому:
    List first = someList();
    List second = someList();
    diff = first.clone();
    diff.removeAll(second);
    

    Но хотелось бы, чтобы такая базовая операция с одним из основных типов данных была из коробки.

    Дальше — одна из наиболее частых задач при работе с коллекциями — это найти нужный элемент в коллекции. Почему List имееет indexOf(Object o), а HashSet не имеет get(Object o), который бы по хеш коду и equals возвращал бы ссылку на обьект из коллекции. Да, когда хеш код не переопределен в этом нету смысла, но когда это не так, то тут уже появляются возможности для использования. Может я, конечно, слишком придираюсь, но довольно часто такая задача возникает.

    Из этого же разряда — нету возможности отфильтровать обьекты по какому-то свойству. Всегда приходится делать это вручную. Плохо, очень плохо.

    Generics

    Map<MyKeyObject, PersistedPlan> plansById = new HashSet<MyKeyObject, PersistedPlan>();
    

    Как уже замечали, такого рода конструкции встречается повсеместно в коде — в описаниях классов, в конструкторах, в методах, везде… Они очень перегружают код и усложняют его восприятие. К счастью, в 7-й java это исправили. Не понятно только — зачем так долго ждали?

    Многопоточность

    Впервые, когда я прочитал про многопоточность в Erlang, я осознал — насколько же механизмы многопоточности java сложны. Все эти locks, monitors, synchronizations, deadlocks, theads, runnables, memory barriers. Зачем? Зачем так усложнять нашу жизнь, ведь java больше 20 лет, неужели трудно рассмотреть тенденции современности? Ведь основная цель java была в облегчении жизни нам — простым разработчикам.
    P. S. Я тут пообщался с коллегами, есть информация, что подвижки в эту сторону идут не маленькие, так что будем надеятся.

    Замыкания

    Частенько возникает необходимость предать функцию в качестве параметра, правда? Сколько можно еще ждать? Мне как java разработчику очень не приятно, что одно из наиболее ожидаемых улучшений так и не сделали. Будем надеятся что хотя бы в 8-й яве появятся, больше тут добавить нечего.

    Runtime and System

    Не совсем понятно логическое разделение этих классов, мне кажется, вполне хватило бы и одного. С System связано еще несколько странностей — например out и in поля класса — final. Но в то же время есть методы setOut и setIn. Плохой пример, не правда ли?

    String

    Очень не эффективен, мало того что 2 байта занимает каждый символ, так еще и каждая строка — это обьект класса String, а это в свою очередь 8 байт на заголовок + 3 целых значения внутри + 1 ссылка на массив == лишних 24 байта на каждую строку! Всё-таки дороговато. Можно было бы хотя бы создать 2 варианта строк: дешевый и дорогой. Был бы выбор хотя бы.

    Numbers

    Long l = 2; //compilation error
    Map<int, Object> a = new HashMap<int, Object>(); //compilation error
    Map<Object, int> a = new HashMap<Object, int>(); //compilation error
    Set<int> b = new HashSet<int>(); //compilation error
    

    Зачем усложнили такие простые вещи? До сих пор не могу осознать. Мелочь, конечно, но не приятно. Дальше — все знают, что для работы с числами с плавающей точкой в яве стандартные примитивы не подходят, так как теряют точность. Хорошо, используем другой тип — BigDecimal. И вот во что превратится простая формула:
    //(metric.getValue() * 100 / prevMetric.getValue()) + metric.getOffset()
    BigDecimal result =BigDecimal.valueOf(metric.getValue() * 100).divide(BigDecimal.valueOf(prevMetric.getValue()).add(metric.getOffset()));
    

    Хорошо если вычисления простые, со сложными все гораздо печальней. Почему не ввести нормально работающий с числами тип данных наравне с double и float?

    Выводы

    Не подумайте, что это некое осеннее обострение. Ни в коем случае. Я очень люблю java и хочу чтобы она развивалась наравне с тенденциями современности. И еще я хочу чтобы на ней можно было программировать в удовольствие, без всех этих мелочей, которые лишь досаждают и отвлекают от занимательной и интересной работы.
    Share post

    Comments 87

      +23
      >> Кто в проекте не использует log4j? А можете сходу назвать библиотеки, которые тоже обходятся без него?

      Те кто используют slf4j и н-р logback

      >> Классы-оболочки — избыточны… Зачем все это?

      Для автоматического boxing и unboxing?

      Если честно, то холиварный пост, и создается ощущение, что автор не до конца разобрался в предмете.
        +1
        Пост о том, что мне не нравится в java в повседневном использовании. Я уверен, что у Вас тоже есть что сказать.
          –5
          Согласен практически со всем, что Вы написали. Мне еще не хватает оверлоадинга операций (как в C#), это решило бы проблемы аналогичные описанной выше с BigDecimal. И даже не знаю, с одной стороны хочется, а с другой стороны понимаю, что читабельность исходников ухудшается, создание объектов в стиле C++:

          вместо: SomeObject o = new Someobject(a,b,c);
          хочется: SomeObject o(a,b,c);
            0
            Не знаю, может стоит тогда уйти с java? Да мне тоже не что то не нравится, например что надо типизировать все коллекции по типу List хотя в самом конце оно всё равно возвращается в List
              +6
              Зачем сходить с джавы? За джаву больше всего платят )
              Ну и все в целом не так плохо — минусы есть, но язык вполне хороший. И в ближайшее время никаких проблем с трудоустройством не будет точно.
                +7
                Как это «зачем» — конкуренция снизится, тем, кто останется, платить станут больше :)
                  –2
                  Ну блин, если не нравится — не пиши, а хочешь писать — не ной.
                  Ничего. Я когда асм учил я плакал и писал, и ничего жив остался.
                  Зачем просто поднимать пост о том что «мне не нравится», а называть «Плохая Java или как делать ненадо».

                  Я вобще очень люблю всё в таком духе. Как в передаче Среда обитания например. говорят что «всё гавно» и «жрать нечего», но не говорят чем можно заменить.
                  Этот пост примерно тоже самое, вот я решил сказать, что можно сделать.
                +1
                Так используйте другие языки под ту же JVM. В чем проблема?
                –3
                >>Для автоматического boxing и unboxing?

                Вы можете посмотреть, как это реализовано в C#. Там, в частности, приведенные автором в пункте «Numbers» примеры будут компилироваться(если, конечно, заменить типы на соответствующие им в .net). Это вдвойне странно, если учитывать, что боксинг был сделан в Java уже после того, как он появился в .net.
                  +1
                  Ничего не странно. Это все для обратной совместимости — чтобы были не примитивы, а субклассы Object.
                  +1
                  Согласен. С рядом его замечаний я согласен полностью, ряд выглядят мелкими придирками.

                  В целом Java как язык весьма ограничена и примитивна, но как developmemt/runtime платформа великолепна по ряду причин.

                  Автор, откройте для себя что Java — это не язык, точнее не только язык. Посмотрите на Groovy, Scala, Jython.

                  Вы жаловались на Switch? Так вот вам как должен выглядить мощный switch:

                  switch (20) {
                  case 2: assert false; break // Равно двум?
                  case 2..15: assert false; break // Попадает в диапазон?
                  case [11,12,14,16]: assert false; break // Входит в список?
                  case Double: assert false; break // является Double-типом?
                  case {it % 5 == 0}: assert true; break // Делится на пять?
                  case ~/../: assert true; break // Матчится regex-y? В эту ветку мы не заходим
                  default: assert false; break
                  }

                    +3
                    Что человек как-то не до конца проникася явой чувствуется когда начинается подсчет байтов,
                    и дисскусия сводится к вопросами экономии их… даже в отрыве от задачи.
                    +4
                    >мало того что 2 байта занимает каждый символ
                    -XX:+UseCompressedStrings

                    Многопоточность такая из-за самой архитектуры языка. Erlang изначально был спроектирован под легковесные потоки.
                      +3
                      Вы путаете 2 парадигмы организации многопоточности: concurrency vs message passing. И та, и другая имеют преимущества и недостатки.
                      В эрланге у одного потока нет доступа к памяти другого потока, поэтому все данные должны передаваться через сообщения. Т.е. здесь вы проигрываете в скорости доступа к данным, но выигрываете в простоте и удобстве. К слову, никто вам не мешает в java использовать общение потоков только через очередь сообщений, не публикуя ссылки на объекты, принадлежащие потоку.
                      –6
                      Еще из претензий к Java: нет generic-методов, информация о параметризации отсутствует во время исполнения.
                        +4
                          –5
                          В Java НЕТ Generics!
                          В отличие от шаблонов C#, шаблоны Java не поддерживаются средой исполнения — компилятор просто создаёт байт-код, в котором никаких шаблонов уже нет. Реализация шаблонов в Java принципиально отличается от реализации аналогичных механизмов в C++: компилятор не порождает для каждого случая использования шаблона отдельный вариант класса или метода-шаблона, а просто создаёт одну реализацию байт-кода, содержащую необходимые проверки и преобразования типов. Это приводит к ряду ограничений использования шаблонов в программах на Java.
                            0
                            Во первых, как Ваш комментарий относится к моему? И во-вторых, то что Вы описали — лишь особенности реализации, которые прикладного программиста касаются в малой степени (лишь в той, где «это приводит к ряду ограничений», да и те ограничения не такие уж существенные).
                              0
                              Если для вас они несущественные — значит Вы никогда не использовали reflection в связке с generics.
                                +4
                                Если приходится использовать generics в связке с reflection — значит что-то не то с вашей архитекторой.
                                  +1
                                  Generic в Java ЕСТЬ, в Java нет того Тьюринг-полного механизма TEMPLATES, который есть в C++.
                                    0
                                    А нужен ли он Яве? Как минимум, один недостаток

                                    > Тьюринг-полного механизма TEMPLATES

                                    — недетерминированность времени компиляции.
                                      +1
                                      Я лично считаю, что не нужен. Достаточно посмотреть сколько времени компилируются сложный темплейтный код на С++… чтобы их возненавидеть.

                                      Сколько времени будет компилироваться код на С++ с темплейтами, в котором скажем 3-4 миллиона строк кода?
                                    0
                                    Все верно, через рифлекшен информацию о типах не достать…
                                      0
                                      Имеется в виду, о генерик типах
                                  +1
                                  В отличие от С# в Java генерики появились только в пятой версии, но при этом новый код с генериками буде скомпилирован запустится и отработает на любой древней jvm, которая о них и не слышала. Обратная совместимость, wright once run everywhere и т.д. и т.п. Это основополагающие принципы java. В молодом C# конечно уже по-другому.
                                  Мне тоже это не нравится, хочется рантайм-генериков и вообще java 2.0 без обратной совместимости. Чтобы ууух сколько классных фич сразу. Но не выйдет, целевая аудитория не та. Java, она для энтэрпрайз мастадонтов, которые может ещё лет десять будут jvm 1.3 использовать потому что масштабы не те и обновиться как у себя на ноутбучеке быстро и просто не получится.
                                    0
                                    Про обратную совместисть хороший поинт. Это очень сильная сторона Java. Я например хорошо помню что .NET 1.0, .Net 1.1, .Net 2.0 были несовместимы. Что в те годы меня дико бесило.
                                      0
                                      Сам-то запускать пробовал? Может и запустится, но не факт что не свалится с каким-нибудь methodnotfoundexception на isEmpty()
                                    –1
                                    Это не то, что я имел в виду. По вышей ссылке идет описание использование generic-параметра класса в методе. В c# метод может иметь свою параметризацию:

                                    public static void Add(T first, T second) {...}

                                    В джаве же Т я должен указывать в объявлении класса.
                                      –1
                                      упс, парсер съел скобки.
                                      public static void Add<T>(T first, T second) {...}
                                        –2
                                        Осторожнее, воинствующий xonix может и Вам минусиков наставить ;)
                                        +4
                                        > В джаве же Т я должен указывать в объявлении класса.

                                        ?

                                        public class C {
                                            public static void main(String[] args) {
                                                someMethod(123, 456);
                                                someMethod(new Object(), new Object());
                                                someMethod("aaa", "bbb");
                                            }
                                        
                                            static <T> void someMethod(T a, T b) {
                                                System.out.println("a=" + a + ", b=" + b);
                                            }
                                        }
                                        
                                        Вывод:
                                        
                                        a=123, b=456
                                        a=java.lang.Object@fa3ac1, b=java.lang.Object@276af2
                                        a=aaa, b=bbb
                                        
                                          +3
                                          хм. Спасибо, я действительно был не прав.
                                            –1
                                            причем даже аргументом указывать не нужно при желании.

                                            public class T
                                            {
                                            public static void main(String[] args) {
                                            String l = T.foo();
                                            }
                                            public static T foo()
                                            {
                                            return (T)(new String());
                                            }
                                            }

                                            простите за стаб в виде new String()
                                              0
                                              хабр съел всю разметку :(
                                    +1
                                    Про свитч: все же они реализовали его немного эффективней, они при компиляции просчитывают hashCode у строк, для всех объектов этого сделать нельзя.
                                    Хоть конечно не понятно что им мешает сделать тупую реализацию, все равно хуже не станет…
                                      +4
                                      Думаю, тут проблема в том что просто_объекты могут быть изменяемыми. Даже если не касаться вопроса оптимизации (нельзя просчитать хэшкод во время компиляции), я даже представить боюсь к чему может привести свитч по изменяемым объектам…
                                      +2
                                      Про Serializable мы имеем следующую проблему: вот Map, к примеру, Serializable или нет? А проблема в том что зависит это от типа ключа и значения, вот и переложили эту проблему полностью в runtime…
                                        +1
                                        Про Collections: ну так обратная совместимость, нельзя так вот просто поменять методы старых классов видимо. Хоть вроде же есть сподвижки в правильную сторону в следующей java? (я про что-то наподобие extension методов).
                                        Про многопоточность: акторы лишь иной способ многопоточности, видимо достаточно хороший, но java.concurrency уже тоже не локи в чистом виде, все же чуть более высокий уровень. Ну и есть Akka.
                                        Про строчки: а что такое дешевые строчки? Храните char array где вам это нужно. Не встречал проблем со String, хоть может быть они и действительно распространенны.

                                        Но вообще очень жаль, конечно, что ява очень медленно развивается.
                                          +9
                                          >гораздо удобней было бы оперировать примитивами и иметь возможность присваивать им null значение. Если простой int занимает 4 байта, то обьект Integer уже целых 16.

                                          Спасибо, не надо. Это только увеличит число NPE (NullPointerException). От этого наоборот стоит уходить. Скажем, меня удивляет, почему еще не добавили поддержку JSR-305 (@Nullable, @NonNull, ...) в компилятор.
                                          И потом, Вы уверены, что если разрешить примитивным типам принимать null, то для int всё еще хватит 4 байта?
                                            +6
                                            Все знают что интерфейс Clonable пустой, без единого метода и переменной, просто маркер для JVM. Вопрос — почему?

                                            Потому что есть такой паттерн — Marker Interface, его цель — именно пометить объект.
                                            Если бы в Object не было метода clone(), то его приходилось бы каждый раз определять самому, а так вам надо переопределять метод clone(), только если дефолтный вас не устраивает.
                                            А если бы Clonable не было, то все объекты по умолчанию считались бы клонируемыми, тогда любой вызов метода clone() мог бы обернуться клонированием огромного графа связанных объектов. Поэтому, когда вы пишете implements Cloneable, вы как бы говорите «Я знаю, что делаю, если будут проблемы — значит сам дурак»
                                              +1
                                              Serializable — то же самое
                                                +5
                                                C Serializable все несколько забавнее.
                                                writeObject() и readObject() предполагаются быть приватными, дабы никто кроме jvm (и соответственно рефлекшена) не имел к ним доступа.
                                                Но как объявить приватные члены интерфейса? Никак…
                                                Именно поэтому пришлось организовать подобную магию.

                                                Можно было бы применить абстрактный класс, но
                                                private abstract void writeObject(); не является допустимой конструкцией также
                                              +11
                                              >> Ведь основная цель java была в облегчении жизни нам — простым разработчикам.
                                              Это вас кто-то обманул. Главное преимущество джавы — надежность и предсказуемость. Ценой многократных, по сравнению с другими языками, усилий разработчиков.
                                                +1
                                                Верно. В частности поэтому на ней пишут в банках, телекоме, на биржах и т.п. И еще, кстати, теперь это производительность, очень хорошая. Уступающая по сути, только C / C++/ Fortran-у.
                                                +2
                                                Добавлю от себя:

                                                — Stack расширяет Vector — по ООП в универе за такое 2 ставят
                                                — CloneNotSupportedException — checked — т.е. нужно обязательно ловить
                                                — InterruptedException — аналогично
                                                — Каждый объект — монитор/лок (wft!)
                                                — и еще что-то можно вспомнить, если постараться

                                                Скорее бы замыкания! Хотя в продакшн из запустить еще не скоро получится.
                                                  +2
                                                  Каждый объект — монитор/лок (wft!)

                                                  Почему вам это мешает?

                                                  InterruptedException — аналогично

                                                  Это очень мощное средство для того, чтоб управлять состоянием треда. Почитайте какую-нибудь хорошую книжку про concurrency в Java, увидите, что это используется довольно часто.
                                                    0
                                                    Мешает мне это потому что в 99% это не нужно. А тот 1% я смогу хэндлить — поэтому и UncheckedException тут намного лучше подходит.

                                                    Для монитора можно было бы сделать объект Lock extends Object с методами wait, notify, notifyAll. И на котором синхронизоваться можно. Так сделано в питоне — и ничего, все нормально.

                                                    Книжки читал.
                                                    • UFO just landed and posted this here
                                                        0
                                                        Да, устраивает.
                                                        Lock использую.

                                                        Я понимаю, зачем сделали все объекты мониторами — для синхронизации на методе. Однако я думаю, что есть решение изящнее. И практика использования того же питона показывает, что действительно есть.
                                                  0
                                                  Еще один интересный момент.
                                                  Класс Number изначально знает обо всех своих детях объявляя у себя методы а-ля:
                                                  public abstract double doubleValue();
                                                  ООП переворачивается в гробу ;)
                                                    +3
                                                    Он вроде бы еще не умер, чтобы переворачиваться )
                                                      +3
                                                      > Класс Number изначально знает обо всех своих детях

                                                      Так можно сказать, что любой абстрактный класс знает о своих детях.

                                                      Класс Number обязывает любого кто осмелился его унаследовать реализовать методы конвертации этих самых наследников в стандартные типы явы (int, float, byte, etc...). По-моему весьма предусмотрительно, т.к. пользователи любых реализаций Number бесплатно получат удобство конвертации в эти типы, а не будет городить каждый раз своё преобразование.
                                                        –1
                                                        Вы неправы, ни один из абстрактных классов не должен знать о специфике своих наследников.
                                                        Он знает лишь об их общих чертах.

                                                        getValue() — общая черта
                                                        getInteger() — специфичная, основанная на том что один из наследников работает с Integer
                                                          +1
                                                          Неправы таки Вы.

                                                          Дело в том, что в природе существует не так много разных Number'ов. Самых основных можно пересчитать по пальцам: byte, double, float, int, long, short. Собственно это и есть список примитивных типов явы. Работая с числами, вы в 99,9% работаете в основном с этими 6ю типами. Вот почему дизайнеры JDK обязали все реализации Number (а их, на минуточку, есть не только в JDK но и в разных там commons.lang и др. библиотеках) реализовывать приведение к примитивным типам — для удобства конечных пользователей этих реализаций Number.

                                                          Если Вам, как программисту очередной реализации Number лень/не хочется реализовывать эти методы — просто не наследуйте Number, делов-то. Только, учтите, что тогда Ваши конечные пользователи не смогут пользоваться удобствами из JDK, скажем, java.text.NumberFormat / DateFormat /… или пакет commons.lang.math и ему подобные, понимающий любой Number именно за счет обязательной реализации этих методов.
                                                            –3
                                                            Зачем это было сделано — очевидно. Мне лишь не нравится реализация где предок знает о потомках.
                                                            Смотрите мое предложение чуть ниже. или реализацию Int32 в C#
                                                            msdn.microsoft.com/en-us/library/system.int32.aspx
                                                            , где (на мое удивление) используется тот же принцип, что и предложенный мной ниже — т.е. каждому числу навязывается набор интерфейсов для возможностей конвертации в другие форматы.
                                                              +2
                                                              > Смотрите мое предложение чуть ниже. или реализацию Int32 в C#
                                                              msdn.microsoft.com/en-us/library/system.int32.aspx, где (на мое удивление) используется тот же принцип, что и предложенный мной ниже


                                                              Что-то Вы опять ошибаетесь. По Вашей же ссылке нет и намёка на отдельные

                                                              > интерфейсы Float/Double/Imteger/etcExportable

                                                              Однако, если открыть документацию к интерфейсу IConvertible: msdn.microsoft.com/ru-ru/library/system.iconvertible.aspx мы увидим, что это та же идея что и в яве, только выделенная в отдельный интерфейс, который (о боже!)

                                                              > изначально знает обо всех своих детях объявляя у себя методы а-ля

                                                              ToBoolean
                                                              ToByte
                                                              ToChar
                                                              ToDateTime
                                                              ToDecimal
                                                              ToDouble
                                                                0
                                                                Пля…
                                                                Вы правы ;)
                                                                И в шарпе фигня и в яве. Обоснованная, необходимая, понятная, но фигня неООП-шная ;)
                                                                  0
                                                                  Всё там нормально и ООПно
                                                                  примитивные типы вообще стоят особняком по отношению к объектной иерархии и к ООП отношения вообще не имеют
                                                          –4
                                                          IMNSHO все должно было бы работать иначе.
                                                          Должны были существовать интерфейсы Float/Double/Imteger/etcExportable, которые бы навязывались классу -реализации Number. Т.е. например:

                                                          class Integer extends Number implements FloatExportable, DoubleExportable, ByteExportable,…

                                                          Так было бы гораздо более по-ООПшному, согласны?
                                                            0
                                                            > которые бы навязывались классу -реализации Number

                                                            Обождите-ка. Как раз текущая реализация навязывает, да. А в Вашем варианте никто не мешает сделать без Ваших *Exportable

                                                            class Integer extends Number { ... }


                                                            и привет.
                                                              –2
                                                              Вы точно внимательно прочитали мой комментарий? ;)
                                                              на всякий случай:
                                                              Integer — класс-реализация Number, и я предложил другой вариант его описания
                                                        –3
                                                        Тот факт что switch работает только со строками, возможно, основан на следующем:
                                                        Switch по сути своей идентичен последовательности if — else, за двумя исключениями:
                                                        — более компактный синтаксис
                                                        — switch быстрее(как минимум был раньше) за счет ограниченной поддержки типов. Возможно работа со стрингАми захардкожена таким образом что equals для стринга проверяется быстрее чем equals для Object.

                                                        p.s. Это предположение
                                                          +5
                                                          а если break не ставить в конце каждого case, то switch уже не так и идентичен if-else.
                                                          0
                                                          «Из этого же разряда — нету возможности отфильтровать обьекты по какому-то свойству. Всегда приходится делать это вручную. Плохо, очень плохо.»

                                                          Хотите как в CriteriaAPI?
                                                            0
                                                            После кодирования на haskell ну очень не хватает tuples из коробки.
                                                              +3
                                                              Кортежи без сопоставления с образцом — малоосмысленная штука.
                                                              0
                                                              про Generics
                                                              " К счастью, в 7-й java это исправили. Не понятно только — зачем так долго ждали?"

                                                              Очень интересно как исправили!
                                                                0
                                                                надеюсь не как в С# через var?
                                                                  +3
                                                                  Параметры справа можно опускать:
                                                                  Map<MyKeyObject, PersistedPlan> plansById = new HashMap<>();
                                                                    0
                                                                    А как же

                                                                    Map<MyKeyObject, PersistedPlan> plansById = newHashMap();

                                                                    из Guava? Или вы в 2011 году не пользуетесь?
                                                                      +2
                                                                      А я в 2011 году пользуюсь Scala.
                                                                        0
                                                                        Принимается :)
                                                                      –3
                                                                      Вроде как и в 6-й(5?) можно писать еще проще
                                                                      Map<Object, Object> m = new HashMap();
                                                                      Map m = new HashMap<Object, Object>();

                                                                      один черт — и первое и второе — фикции, а не женерики.

                                                                      Или оставляя <> получаем какой то профит в проверках?
                                                                        +1
                                                                        Сравните тип слева в приведённом мной варианте из Java 7 и в ваших.
                                                                    0
                                                                    «С System связано еще несколько странностей — например out и in поля класса — final. Но в то же время есть методы setOut и setIn.»

                                                                    Не так красиво как хотелось бы, но вполне разумно.
                                                                    Ни in, ни out не сэтятся напрямую. Их установка происходит в native методах, которым плевать на идентификатор final.
                                                                    Т.е. получается что Вы можете использовать публичные in и out, но можете их изменить только через сэттеры. А в сеттерах (прикрученных много позже появления System.out) проверяются разрешения на установку ввода-вывода.

                                                                    p.s. Да, наличие публичных геттеров и приватных полей было бы красивее.
                                                                    То что есть сейчас — всего лишь одни из самых адекватных костылей к древнему, но широко используемому коду.
                                                                      +3
                                                                      > Почему List имееет indexOf(Object o), а HashSet не имеет get(Object o), который бы по хеш коду и equals возвращал бы ссылку на обьект из коллекции.

                                                                      Потому что, если этот метод зачем-то нужен, то equals реализован неправильно.
                                                                        +32
                                                                        Создается впечатление, что автор имеет весьма и весьма поверхностные знания о Java.

                                                                        HashSet — в большинстве языков программирования, в которых есть множества объектов, они реализованы именно таким образом. Тут не добавить, не убавить — как говориться, вам шашечки или ехать. В большинстве случаев скорость работы структуры данных много важнее ее размера.

                                                                        Вы может быть еще byte используете для чисел? В современном мире byte может понадобиться только при работе с бинарными данными. И то, обычно продолжают использовать int, которому практически на всех аппаратных платформах соответствует машинный тип.

                                                                        Default logger, Clonable, System, Runtime, Properties — результат исторического развития платформы. Шестнадцать лет назад у нас было гораздо меньше опыта построения крупных объектно-ориентированных систем. Джош Блок еще не писал Effective Java — он писал реализацию collections API и сам учился писать правильно. А затем никто уже ничего менять не стал из-за обратной совместимости. И поверьте мне, на сегодняшний день обратная совместимость — основная причина, по которой бизнес не боится использовать Java.

                                                                        Integer, Boolean и т.п. — это результат компромисса между скоростью исполнения и удобством API. Джаве нужны были примитивные типы, которые при этом вели себя нормально с точки зрения объектной модели. Да, в современных языках умеют сделать это элегантнее, а на тот момент могли только так.

                                                                        Switch — каждый Java-разработчик знает, что свич плохо пахнет. Если нужно полиморфное поведение, то в языке уже есть три механизма, его обеспечивающие. Если не хочется городить огород, то:
                                                                        1. Если значения переключателя известны в момент компиляции, используем свитч.
                                                                        2. Иначе — цепочку if else if — смотрится она вполне нормально.
                                                                        Скажете, а как же строковые константы? — а enum на что? Или вы любите stringly-typed-код?

                                                                        Многопоточность: все отлично в Java с многопоточностью, большинство языков нервно курят в сторонке. Java предлагает целый спектр возможностей: от реализаций data-parallelism через Fork/Join и Hadoop, software-transactional memory и actor model в Clojure и Akka до самого низкоуровневого взаимодействия через wait(), notifyAll() и т.п. Эрланг предлагает одно решение, бесспорно хорошее, и считает, что оно подойдет для любой проблемы. Java может все, что и Erlang, даже hot code reload можно реализовать через ClassLoaders. Единственное, что от вас требуется — выбрать наиболее подходящий инструмент для задачи. Подсказываю: wait-notify — не подходящий в 99.99% случаев.

                                                                        String — про Юникод мсье не слышал? Вообще прекращайте уже на байты мастурбировать.

                                                                        Замыкания: зачем ждать? Groovy, Scala, Xtend, Clojure, Mirah, javac.info Выбирайте. Annonymous Inner Classes тоже никто не отменял. Громоздко, но не более.

                                                                        Числа. Точность нужна только для финансовых расчетов. При этом никто не мешает вам использовать long или int и делить на 100 при выводе. Опять же, никто не мешает вам всю работу вести с BigDecimal, а описанный мною способ применять в случае сложных вычислений. В других языках на JVM есть поддержка чисел с фиксированной точкой на уровне синтаксиса.

                                                                        Java немного староват как язык, но отнюдь не плох. Вы вряд ли найдете настолько солидное сочетание скорости работы и огромного объема уже реализованной функциональности. 99% языков до нее не дотягивают: некорректно работают со строками, или с числами, или с датами, многие из них имеют нестабильные реализации, у многих проблема с обратной совместимостью. С другой стороны вас никто не заставляет все делать на одном языке: use right tool for a job.
                                                                        • UFO just landed and posted this here
                                                                          • UFO just landed and posted this here
                                                                          +4
                                                                          Извините, но некоторые моменты просто бредовые. А тотальный подсчет байтиков больше похож на паранойю.
                                                                            –9
                                                                            Меня в Яве огорчает то, что там стандартную библиотеку (rt.jar) разработчики поленились и написали на Яве, а не на Си, например. Отвратительно. Какой в ней смысл? На Яве накривокодить любой может и сам.

                                                                            Ну а switch с объектами и HashMap для объектов — это маразм. Кому без этого совсем никак, приделывает к объекту метод getUniqueId() и не парится.
                                                                              0
                                                                              > на Яве, а не на Си, например. Отвратительно. Какой в ней смысл?

                                                                              Так портируемость же. Чем меньше написано на си — тем легче портировать.
                                                                                +1
                                                                                Очевидная нелепость. Зачем писать стандартную библиотеку Java на С? Как вы будете использовать классы из нее в Java? JNI не поддерживает прямой маппинг между классами Java /C++, и хорошо что не поддерживает.
                                                                                  +3
                                                                                  На самом деле очень немногие компоненты JRE написаны на С. JVM, сама java.exe, интерпрератор байткода, JIT, GC. Из библиотеки классов только в отдельных местах, там где идет работа с IO, threads etc, используются native методы.
                                                                                • UFO just landed and posted this here
                                                                                    0
                                                                                    А меня тоже почти весь ваш список дико бесит в яве. Я с вами. Еще дико бесит одно из ограничений генериков. Я хочу иметь возможность сделать Map<Class, T>, чтобы оно понимало, что я по классу кладу инстанс объекта, а не кастить везде явно. В остальном генерики явы только радуют. А вот про HashSet и все, что с ним связано много можно понаписать, объяснение простое, язык очень консервативный, ибо таков и корпоративный рынок. И хоть я понимаю, почему каждый пункт сделан так как сделан, все равно бесит. И бесит вместо HashSet использовать свою реализацию через HashMap, как раз для того, чтобы не создавать ентри на каждое обновление объекта в коллекции и иметь возможность реализовать метод get(Object o).
                                                                                    Я утешаюсь, что чем проще язык и чем меньше у него конструкций, тем сложнее на нем написать жуткую нечитаемую фигню, с-но проще чужой код на нем читать. А то можно действительно в DSL уйти и прочее метапрограмирование.

                                                                                    Only users with full accounts can post comments. Log in, please.