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

    +78

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    String result = "";
    
    for (Object obj : col) {
        if (obj instanceof String) {
            result += obj + SEPARATOR;
        } else {
            result += obj.toString() + SEPARATOR;
        }
    }
    					
    if (result.length() >= 2) {
        result = result.substring(0, result.length() - SEPARATOR.length());
    }

    instanceof String доставил.
    Кстати, к проекту подключены apache.commons.lang и guava, так что способов сделать join строк предостаточно.

    Запостил: roman-kashitsyn, 19 Июня 2012

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

    • показать все, что скрытоБагры - добры, и бобры - добры, а люди - злы
      Ответить
    • показать все, что скрытоКто это здесь мне минусы въёбывает? Уж прям нельзя со слова "багор" поорать
      Ответить
    • Ну да, а то вдруг toString() от строки приводит к делению на ноль? OH SHI-
      Ответить
      • Ну может OutOfMemory произойти на аллоке лишнего объекта. Отказ от StringBuilderа и ему подобных выдает нуба.
        Ответить
        • Аллока на toString() не будет. Как гласит ман по классу String:

          String toString()
          This object (which is already a string!) is itself returned.
          Ответить
          • Ага, затупил. То на trimах и прочих substringах аллоки новых объектов на старом наследии.
            Ответить
    • меня вконец задолбали подобные join'ы, поэтому просто оставлю это здесь:
      StringBuilder sb = new StringBuilder();
      for (Object obj : col) {
        if(sb.length() != 0) sb.append(SEPARATOR);
        sb.append(obj);
      }
      String result = sb.toString(); // или return sb.toString(); если это утилитный метод
      и somebody beat me! (всмысле, напишите лучше, чем это)
      Сам давно добавил этот метод в самописные утилиты, пользуюсь до сих пор.
      Ответить
      • // Guava
        String result = Joiner.on(SEPARATOR).join(iterable);
        // Apache
        String result = StringUtils.join(SEPARATOR, collection); // or iterator or array
        Но если уж совсем всё грустно, для себя я бы сделал как в Guava (уж очень удобное API).
        Ответить
        • а что там внутри? небось то же самое.
          Ответить
          • http://tinyurl.com/guava-joiner
            Guava Joiner похитрее, ибо поддерживает конфигурацию вида skipNulls и trimResults. Также можно легко джоинить мапы.
            Ответить
            • >Можно джоинить мапы.
              Я дже джва года джу такой джойнер!
              join (map.entrySet(),sep) кроет большинство случаев
              Ответить
              • Просто есть ещё Splitter с похожим интерфейсом, который умеет эти мапы доставать обратно.
                Ответить
            • Джойнить мапы и мапать джойны!
              Ответить
              • сплит твой итератор!
                Ответить
                • Да я твою коллекцию итерировал! ;)
                  Ответить
                  • А файл мне попарсить не хочешь?
                    Ответить
                    • Сокет закрой, сервачок ;)
                      Ответить
                      • Можешь засунуть тот объект себе в коллекцию!
                        Ответить
                      • Я тебе при встрече набью стек - будешь в лог эксепшенами плеваться.
                        Ответить
                        • Слышь экцепшн, ты с какого неймспейса будешь?
                          Ответить
                          • Ша, функции-члены, ну-ка быстро декомпозировались по компонентам!
                            Ответить
                            • Метод себе декомпозируй, класс.
                              Ответить
                              • Слышь, объект, а у тебя итератор есть? Нет? А если найду?
                                Ответить
                                • В конец выродился? Таких как ты у нас быстро декаррируют.
                                  Ответить
                                  • Фильтруй список, не на PHP кодишь.
                                    Ответить
                                    • Я тя найду в мапе!!! Хеш-функцию вычислю, элемент невалидный!!!
                                      Ответить
                                    • Давай свой индекс/ключ, я тебя и отфильтрую и замаплю!!!
                                      Таких как ты, невалидных, я пачками джойнил!!!
                                      Ответить
                                    • До тебя пакетами штоле доходит? Или ты кодировку в потоке попутал?
                                      Такие теги парсеру своёму будешь писать.
                                      Ответить
                          • Ты лучше выбирай уровень логирования, ты хоть знаешь кому ты эти ворнинги пишешь?
                            Ответить
                            • Ты мне тут операторы не перегружай! Страуструпа знаешь?
                              Ответить
                              • За такую кодировку тебя так отдефайнят - препроцессор не поможет.
                                Ответить
                                • Да я с препроцессором на одном этапе компиляции сидел!
                                  Ответить
                                  • Выбирай условия, то можешь и по индексу не пойти.
                                    Ответить
      • Кстати, хочу обратить внимание на один аспект, который LureOfChaos успешно преодолел, а вот автор кода в топике - нет. Если в коллекции лежит null, то instanceof вернёт для него false, и код грохнется с NPE. Поэтому правильней вообще не вызывать toString(), append вызовет его сам с проверкой на null.
        Ответить
      • >somebody beat me!
        Ну это можно улучшать бесконечно, лол
        Я тоже когда-то написал 2 таких метода. И ни в одном из них нет тупой проверки на каждой итерации > if(sb.length() != 0)
        В JDK14 варианте - allow nulls
        // при joine nullы трактуются эквивалетными строке "null"
        	public static String join(Iterator it, String sep)
        	{
        		if (it == null) 	return EMPTY_RESULT;
        		if (!it.hasNext()) 	return "";
        		StringBuilder sb = new StringBuilder(String.valueOf(it.next()));
        		while (it.hasNext())
        			sb.append(sep).append(it.next());
        		return sb.toString();
        	}
        Ответить
      • JDK14 вариант - skipNulls - потом оборачивается методами с меньшим числом параметров - для удобства.

        /**
         * склеивание строк с игнорированием null-овых.
         * 
         * 	длина результата - указание точной длины может существенно ускорить работу 
         * @param size
         * 	итератор со значениями
         * @param it
         * 	разделитель. null-овые значения трактуются как пустая строка
         * @param separator
         * 	заменитель null-а для значенйи из итератора. 
         *  если передаём null - это пропуск.
         * @param nullReplacer
         *  склеенная строка, с разделителями
         * @return
         */
        public static String joinNotNull( int size,
        		Iterator it, Object separator, Object nullReplacer) 
        {
        assert(size>=0);
        	if (null == it) 
        		return EMPTY_RESULT;
        	String 		  sep=	isNull(separator,"").toString();		
        	StringBuilder sb = 	new StringBuilder(max(size,32));
        	
        	for (Object o; it.hasNext(); )
        		if (null != ( o=isNull(it.next(),nullReplacer) )) 
        			sb.append(o.toString()).append(sep);
        	 
        	sb.setLength(max( size, (sb.length()-sep.length()) )); //обрезка последнего sep
        	
        	return sb.toString();
        }
        Ответить
    • мой велосипед, от варианта Lure не отличается, скорее, то что имею две сигнатуры - с Collection и vararg
      public static String join(String separator, Object... elements) {
      		StringBuilder result = new StringBuilder();
      		for (Object o : elements) {
      			if (o != null) {
      				if (result.length() > 0) {
      					result.append(separator);
      				}
      				result.append(o);
      			}
      		}
      		return result.toString();
      	}
      	
      	public static String join(String separator, Collection<?> objects) {
      		return join(separator, objects.toArray());
      	}
      Ответить
      • Имхо надо бы наоборот - первый джойн выразить через второй.
        Ответить
        • просто в коде первый раз потребовалось в виде Strings.join("\n", "a", "b", "c"), поэтому так
          Ответить
        • забыл спросить: и в чем преимущество?
          Ответить
          • Не будет лишнего вызова toArray() во втором варианте, и смотрится приятней.
            Ответить
            • тогда будет лишнее преоразование с vararg
              Ответить
              • А разве "Object... elements" не массив?
                Ответить
                • массив, но массив это не Collection<?>
                  Ответить
              • Ну и в varargs варианте всяко будет меньше 10 элементов, а в collection варианте может быть и 1000 и 10000...
                Ответить
                • в массивах тоже могут быть тысячи элементов. то что метод объявлен как vararg, совсем не отменяет того, что он может вызываться как join(separator, array)
                  Ответить
        • Iterator/able - самая универсальная штука. Всё остальное выражается через него.
          Глянул одним глазом в сырцы гуавы - даже в гугле с этим согласны:
          public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
              checkNotNull(appendable);
              if (parts.hasNext()) {
                appendable.append(toString(parts.next()));
                while (parts.hasNext()) {
                  appendable.append(separator);
                  appendable.append(toString(parts.next()));
                }
              }
              return appendable;
            }
          Ответить
          • эт ясен пень, что выражается. универсальность, конечно, хорошо, но свой join(sep, v1, v2, v3, v4, ...) не променяю ни на что. люблю его именно за краткость и отсутствие шума в виде создания промежутончых коллекций или чего-нить подобного
            Ответить
            • > свой join(sep, v1, v2, v3, v4, ...) не променяю
              public static String join(Object sep, Object... parts) {
                 return join(sep, Arrays.asList(parts));
              }
              Ответить
              • это то понятно, в чем плюс join реализовать именно в Collection, а не в varargs?
                Ответить
                • http://govnokod.ru/11230#comment143165
                  Ответить
                • asList - это view массива как коллекции, потребляющее O(1) памяти. toArray создаёт новый массив, т.е. требует O(n) памяти. Вычислительная сложность одинаковая. Следовательно, явное преимущество у реализации через Iterable.
                  Ответить
                  • Спасибо, что разжевываешь (мне меньше писать), хочу только добавить, что итератор - он универсален, им можно обернуть что угодно, хоть ResultSet, хоть InputStream - не создавая промежуточных сущностей.
                    Итераторы же это и есть сама по себе концепция ленивых вычислений.
                    Ответить
                    • ключевая фраза - "можно обернуть". не люблю оборачивать там где не надо, засоряет код. это не означает, что я не пользуюсь итераторами и выступаю против них :) И если у меня будет подключен какой-нить фреймворк, то join(s, args...) соответственно будет реализован как делегат к фреймворку.
                      Ответить
                      • Я довольно часто использую композиты, особенно после того, как стал увлекаться функциональщиной.
                        Ответить
                        • java не тот язык где можно элегантно оперировать коллекциями
                          Ответить
                          • были бы лямбды - можно было бы. И всё же я периодически использую transform и filter, правда, только с часто повторяющимися предикатами и функциями. Пример из последнего:
                            String [] campaignKeys = toArray(transform(campaigns, makeCampaignKey), String.class);
                            count = jedis.sunionstore(tmpKey, campaignKeys);
                            Ответить
                            • P.S. А вот принимал бы sunionstore Iterable, промежуточный массив бы не понадобился.
                              Ответить
                              • а вот бы еще реализовывал массив Iterable...
                                Ответить
                            • лямбд к сожалению нет :( ждем Java 8
                              Ответить
                              • ждем java 9 и перегрузку операторов с Dynamic классами
                                Ответить
                                • Лучше юзаем Scala уже сегодня
                                  Ответить
                                  • what about Groovy?
                                    Ответить
                                    • Мне нравятся языки, в которых есть идея. У Scala - component abstraction (+ типы, пирожки и функциональщина, но это скорее следствия). У Clojure - современный лисп с мощной поддержкой многопоточности (STM), макросами и интеграцией с Java. А Groovy - это та же Java, но с вкусными плюшками. Ну да, метаклассы и намёки на метапрограммирование. Множество мелких улучшений, делающих жизнь немного приятней, но не меняющих парадигмы.

                                      ОБС: вроде бы создатель Groovy так проникся Scala, что заявил, что не стал бы делать Groovy, если бы узнал о Scala вовремя.
                                      Ответить
                                      • А вот и пруф:
                                        "I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy."
                                        http://tinyurl.com/ops4wd
                                        Ответить
                                    • Сайт груви настолько же тормозной, как сам язык.
                                      Груви не нужен!
                                      Динамическая типизация не нужна!
                                      Ответить
                                      • > Динамическая типизация не нужна!
                                        Из-за статической типизации появляются такие запутанные и тормозные штуки, как reflection.
                                        Ответить
                                        • reflection не нужен нужен редко, пускай будет тормозным и запутанным.
                                          Ответить
                                        • Пусть один процент кода будет сложным и запутанным (рефлексия, да). Но не весь же, как в динамике!

                                          А если есть метапрограммирование, то рефлексия не нужна. Хай живе Немерле!
                                          Ответить
                                          • а что сложного в динамической типизации?!
                                            Ответить
                                          • а что сложного в динамике?
                                            вот, к примеру,вызов метода по имени;
                                            js:
                                            var obj = {
                                              m : function() {}
                                            }
                                            
                                            var s="m";
                                            obj[s]()
                                            почему в java я для того же эффекта должен писать
                                            class Cls {
                                              void m() {}
                                            }
                                            
                                            Cls obj=new Cls();
                                            String s="m";
                                            Cls.class.getMethod(s).invoke(obj);
                                            тут даже php смотрится почти хорошо:
                                            class Cls {
                                              function m() {}
                                            }
                                            
                                            $obj=new Cls;
                                            $s="m";
                                            $obj->$s();
                                            смотрите, какая запись понятнее?

                                            и это простой пример, а обычно нужно еще сложнее - скажем, недавняя реальная задача:
                                            у данной неизвестной JPA сущности @Entity, чей класс задан generic'ом<E>,
                                            нужно найти ее свойства, заданные либо public полями xxx, либо public геттерами getXxx(), за исключением getClass(),
                                            с последующими чтением\записью из\в свойства по их имени "xxx",
                                            перед этим проверяя возможность доступа конкретного User'a по его ролям, и ролям, перечисленным в аннотации @Roles({"role1","role2"}) к свойству (в поле или аксессоре).

                                            воот. на самом деле там еще веселее, задача создать CRUD юзеринтерфейс для сущностей :З
                                            Ответить
                                            • Не так уж и сложно, кстати. До конкретного типа в дженерике, правда, добраться можно будет не всегда. Ну и код немного громоздкий.
                                              Ответить
                                              • не сложно, но громоздко. мне больше нравится динамическая типизация с контролем типов по желанию, примерно так, как это сделано в питоне
                                                Ответить
                                                • > с контролем типов по желанию
                                                  > как это сделано в питоне
                                                  Не совсем понял по поводу питона... Идеологически там строгая динамическая типизация. Т.е., к примеру, сложить строку с числом нельзя. Это всё полито сверху утиной типизацией. В целом довольно удобно.

                                                  Задача, описанная выше, решается на питоне достаточно просто при использовании метаклассов (или декораторов, хотя метаклассы тут вроде больше подходят). В Django кажить реализовано практически тоже самое.
                                                  Ответить
                                                  • видимо, я все же сфейлился с питоном; я имел ввиду то, к чему мучительно ведут пхп:
                                                    если переменная, поле или параметр метода обьявлен с типом, то далее тип контролируется. если же обьявление идет через def/var, то тип может меняться во время выполнения.
                                                    Ответить
                                                  • Не понял, что это за динамическая типизация, не дающая сложить строку и число? Что же в ней тогда можно такого, чего нельзя в статической?
                                                    Ответить
                                                    • > Что же в ней тогда можно такого, чего нельзя в статической

                                                      Очень много всего. Например, выбирать реализацию модуля, который нужно загрузить, в рантайме.
                                                      if condition:
                                                          import module1 as api
                                                      else:
                                                          import module2 as api
                                                      api.make_me_happy()
                                                      Можно вызывать метод по имени, вот пример прокси:
                                                      class Proxy(object):
                                                          def __init__(self, instance):
                                                              self.instance = instance
                                                      
                                                          def __getattr__(self, attr):
                                                              # do something
                                                              return getattr(self.instance, attr)
                                                      proxy = Proxy(my_obj)
                                                      proxy.do_stuff() # will call my_obj.do_stuff()
                                                      Или, например, можно переопределить способ создания класса: метакласс получает на вход то, что определил пользователь в коде, может поглядеть аттрибуты и методы, добавить новых или заменить поля (как, например, делает ORM Django). Так можно осуществлять автоматическую генерацию boilerplate кода прямо в рантайме.
                                                      Ответить
                                            • >смотрите, какая запись понятнее?
                                              Джавовская. Сразу понятно, что делается что-то зафигавыкрученное. Другое дело, если по каким-то причинам такие операции должны быть все время...
                                              Ответить
                                              • > Сразу понятно, что делается что-то зафигавыкрученное
                                                Ага, особенно, если дописать обработку всех checked exceptions, иначе код не скомпилится.
                                                Ответить
                            • >jedis
                              Джедаи.
                              Ответить
                              • Зная мой извращённый вкус, гугл первой ссылкой всё же показывает вот эту, правильную
                                https://github.com/xetorthio/jedis
                                Ответить
                                • >campaigns
                                  Я подумал что это какая-то игрушка из серии star wars.
                                  Ответить
                                  • Всё проще - рекламные кампании
                                    Ответить
                                  • > sunionstore
                                    Хранилище солнечных ионов?
                                    Ответить
                                    • Отличная интерпретация :)
                                      Set Union Store
                                      http://redis.io/commands/sunionstore
                                      Ответить
                                      • >Хранилище солнечных ионов?
                                        Ну я тоже так прочитал. Если смотреть с точки зрения зв - логично.
                                        Ответить
                      • >ключевая фраза - "можно обернуть". не люблю оборачивать там где не надо
                        Там действительно толковые парни:
                        Whenever possible, Guava prefers to provide utilities accepting an Iterable rather than a Collection. Here at Google, it's not out of the ordinary to encounter a "collection" that isn't actually stored in main memory, but is being gathered from a database, or from another data center, and can't support operations like size() without actually grabbing all of the elements.
                        Ответить
                  • ясно, спасибо за объяснения. когда будут проблемы с производительностью и памятью, тогда поправлю.
                    Ответить
    • показать все, что скрытоКГ/АМ! (спойлер: ОП - ХУЙ!)
      Ответить

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