1. Java / Говнокод #13102

    +114

    1. 1
    switch (Strings.nullToEmpty(value)) { ... }

    Жабовский string switch не умеет в null. Приходится так.

    Запостил: someone, 04 Июня 2013

    Комментарии (131) RSS

    • показать все, что скрытоЖабопроблемы?
      Ответить
    • показать все, что скрытоу null нет хэшкода же
      Ответить
      • показать все, что скрытоnullпроблемы
        Ответить
      • показать все, что скрытоКак это нет?

        Всё, что работает с хэш-кодами, считает, что хэш-код null равен 0.
        Ответить
        • показать все, что скрытоа не null.hashCode() throws NullPointerException?
          Ответить
          • показать все, что скрытоЗачем делать null.hashCode(), если есть Objects.hashCode(null)?
            Ответить
            • показать все, что скрытопотому что, наконец, оракловцы задумались, какой это идиотизм - бросать исключение, если первый аргумент нуллевой.
              Ответить
              • показать все, что скрытоЕМНИП, в жабе любой метод - виртуальный, поэтому при нулевом аргументе неизвестно что надо вызывать
                Ответить
                • показать все, что скрытокроме статических. equals - хороший кандидат на статику
                  Ответить
                  • показать все, что скрыто>equals - хороший кандидат на статику
                    а как переопределять сравнение объектов? Все равно помимо статики QObject.equals(Object) необходим
                    Ответить
                    • показать все, что скрытодля каждого класса свой вариант, иначе используется дефолтный
                      Ответить
                    • показать все, что скрытомда, Qt головного мозга
                      Ответить
                    • показать все, что скрытоА так и переопределять, как сейчас делается. Objects.equals(a, b) эквивалентно:

                      (a == null ? b == null : a.equals(b))


                      Похожий подход используется в Python. Там есть глобальные функции str и repr, которые для классов дёргают переопределяемые методы __str__ и __repr__ соответственно.
                      Ответить
                      • Фитон вообще пропагандирует функции вместо методов.
                        Ответить
                        • показать все, что скрытоШёл 2013 год....
                          Ответить
                          • показать все, что скрыто> Шёл 2013 год...
                            А вот я с ним согласен. Не надо делать кумира из ооп. Некоторые алгоритмы намного лучше смотрятся как функции, чем как статик методы говноутилитарного класса.
                            Ответить
                            • показать все, что скрытоОдна из вещей, которые мне гораздо больше нравятся в с++ (по сравнению с java) - наличие функций, не привязанных к классу.
                              Ответить
                              • показать все, что скрытоimport static же.
                                Ответить
                                • показать все, что скрытодаже не близко:
                                  В c++ такую функцию:
                                  1. можно перегрузить в другом заголовочном файле
                                  2. передавать по указателю в алгоритмы и функции высшего порядка
                                  Ответить
                                  • показать все, что скрыто> можно перегрузить в другом заголовочном файле

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

                                    > передавать по указателю в алгоритмы и функции высшего порядка

                                    Дождитесь Java 8 с лямбдами. А пока есть интерфейсы и анонимные классы.
                                    Ответить
                                    • показать все, что скрыто> полиморфизм и интерфейсы
                                      Видимо, вы просто никогда не писали шаблоны.

                                      > Дождитесь Java 8 с лямбдами
                                      Но в сишке передавать указатели на функции можно уже больше сорока лет, почему я должен ждать до 2015 года?
                                      А java 8 позволит автоматически конвертировать тысячи уже написанных статических методов в замыкания?
                                      Ответить
                                    • показать все, что скрытоПерегрузка - это одно из проявлений полиморфизьма.
                                      Ответить
                                    • показать все, что скрыто>Дождитесь Java 8 с лямбдами.
                                      Это фактически ничего не изменит.
                                      Просто чуть меньше писать. Будет больше функцианального говна, в тех местах где громоздкость не давала развернуться буйной фантазии.
                                      There is no silver bullet, Neo.

                                      > в сишке передавать указатели на функции можно уже больше сорока лет
                                      Архиверно.
                                      Ответить
                                      • а в си в этих указателях не поддерживается наследование. И толку от них после этого?
                                        Ответить
                                    • >Дождитесь Java 8 с лямбдами.
                                      Хахахаха, еще 10 лет подождать? :DDDDDDDDDDDDDDDDD

                                      >почему я должен ждать до 2015 года?
                                      Потому, что ява. Ты еще спроси, когда лямбды появятся.
                                      Ответить
                                      • показать все, что скрытоЕсли ты думаешь, что с питоном все распрекрасно, то ты очень далёк от истины. Довольно часто я предпочитаю жабу питону, даже когда у меня есть выбор (а он у меня есть практически всегда).
                                        Ответить
                                        • показать все, что скрыто>Если ты думаешь, что с питоном все распрекрасно
                                          А причем тут питон?

                                          >Довольно часто я предпочитаю жабу питону
                                          Чего так? И в каком смылсе, "предпочитаю". Жаба ведь тоже далеко не идеальный язык.
                                          Пилить скрипты на питоне - самое то. Тут я предпочитаю питон башу и пёрлу. Смо по себе сравнение динамикм с классической статикой - некорректно.
                                          А так, ну по-просту, тормознутость - его основная проблема.
                                          Ответить
                                          • показать все, что скрытоК примеру, возникла у меня тут задачка - измерить скорость индексации ElasticSearch в зависимости от различных значений некоторых конфигурационных параметров и вообще поглядеть на его профиль во время индексации.
                                            Написал на питоне скрипт за полдня, который в несколько потоков заливает данные. И ещё полдня, @**a, пытался завести его на сервере без интернета и с устаревшей версией питона, взывая к virtualenv, buildout и божьей силе.

                                            В итоге плюнул, написал за теже полдня аналог на жабе, собрал убержар, профит.
                                            Ответить
                                            • показать все, что скрытоХм. Понятно.

                                              > пытался завести его на сервере без интернета и с устаревшей версией питона
                                              /me кстати недавно сталкивался с той же проблемой.
                                              ЧСХ решил тоже жабой :)
                                              Ответить
                                              • показать все, что скрытоК слову, скрипт, который запускает бенчмарк с 100500 различными наборами параметров, бережно собирает полученные чиселки в таблички латех-документа, вставляя попутно сгенерённые по этим данным gnuplot-графики, я написал таки на питоне. Но там не нужны были зависимости.
                                                Ответить
                • показать все, что скрытоПро CLOS можно то же самое сказать (все методы виртуальные - это конечно не обязательно, и стандарт этого не требует, т.е. компилятор может и заинлайнить, но гарантировано заинлайнить произвольный метод наверное не получится).
                  Да, так вот, там методы можно специализировать на null, т.е. если сильно хочется nil с чем-то сравнить, то можно:
                  (defmethod null/equals ((this null) that)
                    (null that))

                  вот так, например.
                  Ответить
    • показать все, что скрыто>Жабовский string switch
      Не нужен.
      Ответить
      • показать все, что скрытоесли посмотреть - то он грамотно сделан. сначала по хэшкоду, и заключительно - полнотекстовым сравнением
        Ответить
        • показать все, что скрытоА как иначе-то? Хеш вычисляется один раз, (за небольшим исключением).
          Хеш-мапы точно так же были сделаны. Еще 15 лет назад.
          Такое горбатое сишкоблядское рудиментарное убожество как switch не исправят никакие строки. Только могила, только хардкор.
          Ответить
          • показать все, что скрытовот и мне странно, что свитч по строкам в жабе сделали только сейчас.
            Ответить
            • показать все, что скрытоДа потому что он нахер никому не нужен. Наверняка спёрли из шарпа.

              А вот чтоб решить действительно нужные, насущные проблемы: сделать грамотные строки, разбитые на страницы по 4К и решить проблему +=, буферов и subString() на больших строках. Это не.

              Ради разминки рекомендую подумать, сколько раз нужно скопировать данные туда-сюда чтобы максимально эффективно считать InputStream в строку?
              Ответить
              • показать все, что скрыто> Наверняка спёрли из шарпа.
                или наоборот. в любом случае, они тырят друг от друга. и это хорошо.

                > чтобы максимально эффективно считать InputStream в строку
                зависит от размера буффера.
                Ответить
                • показать все, что скрыто>зависит от размера буффера
                  Любой разумный для универсального использования. Главное - максимально эффективно.
                  Ответить
                  • показать все, что скрыто1024 байт обычно хватало
                    Ответить
                    • показать все, что скрытоНу и сколько копирований чтоб считать метр?
                      Даю подсказку - эти буфера по 1024 аппендятся в StringBuffer, который потихоньку удваивается копированием.
                      После чего содержимое буфера опять-таки копируется! В новую строку.
                      Ответить
                      • показать все, что скрытосмотря какой длины строки.
                        обычно хватает такой.
                        скажем, для реализации таких протоколов, как HTTP или IRC
                        длинные данные, как правило, бинарные, для них нужен чистый стрим.
                        Ответить
                        • показать все, что скрыто>смотря какой длины строки.
                          Далеко ходить не буду: размер данной страницы - 55 Кбайт.

                          > для них нужен чистый стрим.
                          И сильно со стримом что-либо сделаешь? Регэкс там наложить или найти чего.

                          Еще раз вопрос:
                          >сколько раз нужно скопировать данные туда-сюда
                          Ответить
                  • показать все, что скрытоВообще МАКСИМАЛЬНО эффективно - узнать размер файла, прочитать его за одну операцию в byte[] и весь массив скормить строке вместе с нужной кодировкой.

                    Если просто из потока читаем - начинаем с буфера любого "разумного" размера и при каждом чтении увеличиваем размер вдвое, число перераспределений памяти O(log(len(stream))) + 1.

                    Кстати, шок, хоррор, срочно в номер: StringBuilder так и делает.
                    Ответить
                    • показать все, что скрыто> и при каждом чтении увеличиваем размер вдвое
                      Спасибо кеп.
                      Выше об этом сказано:
                      http://govnokod.ru/13102#comment179590

                      В целом же получаем. Как минимум 3 копирования:
                      1. в массив char[]/byte[]
                      2. в StringBuilder
                      3. в String.

                      А можно-то было обойтись всего одним! То бишь по-прежнему основным двигателем прогресса остаются не сахарные технологии, типа свичей по строкам, а алгоритмы.
                      Ответить
                      • показать все, что скрытоЗачем тут вообще использовать StringBuilder? Если операция критичная по производительности, держите свой собственный расширяющийся массив. Тогда копирований будет только по одному на каждую операцию расширения + одно последнее копирование в String.

                        Хотя, конечно, это недоработка, что StringBuilder не умеет сам эффективно читать из потока. Тут бы пригодился метод, умеющий передавать Reader.read сразу слайс внутреннего массива StringBuilder.

                        (Именно Reader. Если мы читаем из InputStream, то byte[] в char[] всё равно кому-то придётся перекодировать.)
                        Ответить
                        • показать все, что скрытоа зачем StringBuilderу уметь читать из потока? для этого есть вполне эффективные Readerы
                          Ответить
                          • показать все, что скрытоНезачем.
                            Но проблема как раз в том что StringReader неэффективен.
                            Он содержит внутри себя оный StringBuilder.
                            Ответить
                            • показать все, что скрытоНи в StringReader, ни в InputStreamReader нет встроенного StringBuilder'а. В BufferedReader.readLine, да, есть StringBuffer. Увы.

                              > а зачем StringBuilderу уметь читать из потока? для этого есть вполне эффективные Readerы

                              Reader'у нужен массив, в который он будет писать прочитанные символы. Массив приходится выделять самостоятельно и делать StringBuilder.append, а это операция копирования. Было бы более удобно, если бы можно было скормить Reader'у напрямую внутренний массив StringBuilder'а с нужным смещением.

                              Как, например, в MFC CString есть операция GetBuffer, хотя вообще, конечно, MFC - тот ещё ужас.
                              Ответить
                      • Кого и при каких условиях это ебет? Может, ты еще посмотришь, сколько хуйни делают динамические языки?
                        Ответить
                    • показать все, что скрыто> узнать размер файла
                      А если это сокет или пайп? Самый эффективный способ, это как выше написал 3.14159265, паровозик из буферов по N байт.
                      Ответить
                      • показать все, что скрытоДо них никак не доходит, что можно сделать лучше чем стандартное Г. И O(1) оставить, и утечку закрыть.

                        И ведь все эти идеи древнее, придуманы в 70-х или того раньше. Зато хотим бесполезные свичи по строкам.
                        Ответить
                        • Я думаю, суть в том, что в яве нельзя сделать иммутабельный массив, чтобы передать его в другое место. Enjoy your java.
                          Ответить
              • показать все, что скрыто> Да потому что он нахер никому не нужен.

                Прикажете писать портянку из if("текст".equals(str)), которая к тому же медленнее свича?

                > сделать грамотные строки, разбитые на страницы по 4К

                Создаём тыщу строк по одному символу, и привет, внутренняя фрагментация. Типичная строка в типичном приложении гораздо короче 4K.

                Раньше такая проблема была из-за "оптимизации" substring, когда маленький substring от большой строки держал в памяти всю большую строку. Сейчас это убрали.
                Ответить
                • показать все, что скрыто>Создаём тыщу строк по одному символу
                  Будет тысяча строк с массивом на один символ.
                  Ответить
                • показать все, что скрытои привет фрагментация.
                  вообще, это очень холиварный вопрос.
                  я лично думаю, что так сделали, потому что редко кого интересует реализация виртуальной машины, и делают обычно все примитивно. грустно, но факт
                  Ответить
                • показать все, что скрыто>Раньше такая проблема была из-за "оптимизации" substring
                  Хорошая годная была оптимизация. Раньше substring был O(1) - явное следствие COW.
                  И весь старый код заточен на это.
                  Теперь же начиная с богомерзкой 7-й явы O(N).
                  ИМХО, сделали еще бОльшее Говно.
                  Ответить
                  • показать все, что скрытоБерём строку в стопицот символов и оставляем substring на один символ. Весь массив висит в памяти. Абстракция потекла.

                    > Раньше substring был O(1). И весь старый код заточен на это.

                    Затачиваться на детали реализации - ССЗБ. В документации где-нибудь написано, что substring должен быть O(1)?

                    Хотите O(1) - пишите свой substring, это даже не так сложно.
                    Ответить
                    • показать все, что скрыто>Весь массив висит в памяти. Абстракция потекла.
                      Рекомендую внимательно прочитать мои посты выше.

                      >Берём строку в стопицот символов и оставляем substring на один символ.

                      Берём строку в стопицот символов обрезаем джва проблема сначала и с конца.
                      Теперь у нас две практически идентичных строки по 100500 символов.
                      Еще неизвестно что хуже. Перерасход памяти адский, но зато стал явным!
                      Ответить
                    • показать все, что скрыто>Хотите O(1) - пишите свой substring
                      Хотите нормальных строк - пишите сами.
                      Нормальный такой библиотечный подход, да.
                      Ответить
                      • показать все, что скрытоЕсть же ByteBuffer и CharBuffer, которые как раз для таких вот низкоуровневых операций. В том числе в CharBuffer есть честный subSequence.

                        В Обычной Жизни (tm) substring за O(1) - слишком узкоспециализированная операция, чтобы ради неё таскать аж два дополнительных поля и риск внутренней фрагментации.
                        Ответить
                        • показать все, что скрыто>Есть же ByteBuffer и CharBuffer, которые как раз для таких вот низкоуровневых операций.
                          Ну-ка покажите мне как с их помощью искать регэксом в стриме. Или сделать простой replace.
                          Особенно интересует поиск на границах буферов.
                          Ответить
                          • показать все, что скрытоCharBuffer реализует CharSequence, поэтому Pattern может в нём искать.

                            replace - только в строку, но тут-то хоть как придётся выделять новый массив, что с CharBuffer, что с substring.
                            Ответить
                            • показать все, что скрыто>поэтому Pattern может в нём искать.
                              Особенно интересует поиск на границах буферов.
                              Ведь ваш CharBuffer явно не бесконечный.
                              Ответить
                              • показать все, что скрытоsubstring тут тоже ничем не поможет.
                                Ответить
                                • показать все, что скрытоsubstring - это не проблема, а следствие.
                                  Проблема в том чтобы делать что-то нормальное с набором байт из потока нужно сначала сделать кучу ненужных копирований...
                                  Ответить
                                  • показать все, что скрытоВы уж определитесь, вам "шашечки или ехать". И какая конкретная задача.

                                    Достаточно простые случаи можно скормить Scanner. Для остального есть jakarta regexp, который поддерживает поточную обработку.

                                    Конкретно у меня речь шла о том, что аналог O(1) substring в стандартной библиотеке есть. Что ещё надо?
                                    Ответить
                                    • показать все, что скрыто>Достаточно простые случаи можно скормить Scanner.
                                      То еще говно. Причем несмотря на CharBuffer и nio тормознутее чем остальные io способы.
                                      Достойно отдельного треда.

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

                                      И, сюрприз! начинает применять регэкс на новом буфере с самого начала (или места последнего матча).

                                      Короче копирований там дохерища. Еще и шлемиэльщина.

                                      >есть jakarta regexp, который поддерживает поточную обработку.
                                      Да есть много third-party либ.

                                      Изначально же говорилось - они занимаются херней какой-то, вместо того чтобы сделать нормальные стандартные строки, io и буфера.
                                      Ответить
                      • показать все, что скрыто> Хотите нормальных строк - пишите сами.
                        Data.ByteString наше всё
                        Ответить
                        • показать все, что скрытоБлин. А я только писал ответ сюда:
                          >"Нормальные стандартные строки" - это какие?
                          Что в хацкиле строки настолько хорошо зделаны. Практически образцово.
                          На io вполне запросто могут уделать по памяти/cpu жабу, шарп и кривые самописные крестоподелия. И это несмотря, на иммутабельность!

                          Плюс. Думаю зеленый цвет тут не нужен.

                          append :: ByteString -> ByteString -> ByteStringSource O(n).
                          Хотя нет уж. Rope наше всё.
                          Ответить
                          • показать все, что скрытоData.Rope в помощь
                            Ответить
                            • показать все, что скрытоНичего не понимаю. И это программисты? Говно какое-то, обезьяны блядь. Ученые им придумали структуру, используй, используй алгоритм блядь, не хочу, хочу писать O(N) говно. Что такое? Это жаба? Это шарп? Суки, мудачьё - subString усложнили, сахар жрут. Пидоры блядь ёбаные.
                              В жабе алгоритмическая культура развита только там где код пишут люди с учеными степенями - java.utl.concurent. В шарпе она вообще практически отсутствует - не было наборов до 3.5. Хацкиль выглядит оплотом алгоритмики и за счёт неё может запросто уделать их.
                              Ответить
                • показать все, что скрыто>Прикажете писать портянку из if("текст".equals(str)), которая к тому же медленнее свича?
                  Приказываю разбираться с хеш-мапами и енумами.
                  Ответить
                  • показать все, что скрытоХэш-мапы - не особо хорошая замена свичам, ибо часто нужно котнекст захватить, недоступный хэш-мапе. Если надо действия на строки повесить - это большая куча бойлерплейта.
                    Мне не особо нужен свитч по строкам, но и хэш-мапа не всегда подходит.
                    Ответить
                    • показать все, что скрыто>Если надо действия на строки повесить - это большая куча бойлерплейта.
                      Енум. Просто добавь valueOf(String).
                      Ответить
                    • Горько плачет жаваблядь,
                      Век замыканий не видать,
                      Литералов для хешмепов тоже не видать.
                      Поебать!
                      Фабрика легко и непринужденно
                      Помещается в очке.
                      Что нужно еще?
                      Ответить
          • показать все, что скрыто> Хеш вычисляется один раз, (за небольшим исключением).

            Кстати, не пойму, почему они выбрали 0 в качестве специального значения.

            Не проще ли было бы сделать хэш типом Integer вместо int и использовать null как флаг "хэш ещё не закэширован"?
            Ответить
        • Если посмотреть - это захардкоженый hashmap.
          Ответить
      • О, жаваблядь вылезла. Тебе и foreach не нужен, что ж на ассемблере не пишешь?
        Ответить
    • показать все, что скрытоШкололо научилось писать циклы и отправлять POST запросы. Прогресс.
      Ответить
    • показать все, что скрытоДобавление строки в сущ букмарклете избавляет от неудобств.
      $('.ajax').closest(":not([href=http://govnokod.ru/user/5798])").trigger('click');
      Ответить
    • показать все, что скрытоКакому-то вандалу явно нечего было делать.
      Ответить

    Добавить комментарий