Отслеживание того, что находится в коллекции в пре-дженериках Java? - PullRequest
4 голосов
/ 28 мая 2011

По ряду причин, которые (верьте, хотите нет) не настолько несостоятельны, как вы думаете, мы все еще ( вздох ) используем Java 1.4 для сборки и запуска нашего кода (хотя мы планируем наконец-то перейдем на Java 7 к концу года).

Наш существующий код, который использует классы Collection, не очень хорошо показывает, что ожидается в Collection. Очевидно, что вы можете прочитать код и увидеть, что в итоге делают downcast, и сделать из этого вывод, но вы не можете просто посмотреть на объявление метода и узнать, что на самом деле является Collection объектом, который является аргументом метода или методом, возвращающим значение держит.

В новом коде, который я пишу, и когда я нахожусь в более старом коде, который использует Collection s, я добавляю встроенные комментарии к объявлениям Collections, чтобы показать, что было бы объявлено, если бы генерики использовались используемый. Например:

Map/*<String, Set<Integer>>*/ theMap = new HashMap/*<String, Set<Integer>>*/();

или

List/*<Actions>*/ someMethod(List/*<Job>*/ jobs);

В соответствии с хмурым отношением к субъективности здесь, в SO, вместо того, чтобы спрашивать, что вы думаете об этом (хотя по общему признанию я хотел бы знать - я нахожу это немного уродливым, но все еще хотел бы иметь там информацию о типах) вместо этого просто спросите, что, если что-нибудь, вы делаете, чтобы прояснить, что удерживается префиксами Collection объектов.

Ответы [ 4 ]

4 голосов
/ 28 мая 2011

То, что мы рекомендовали в прежние времена - а я был Java-архитектором в Sun, когда Java 1.1 была новой вещью, - это написать класс вокруг структуры (я не думаю, что в 1.1 даже была Collection как базовый класс), чтобы типы выполнялись в коде, которым вы управляете, а не в коде пользователя. Так, например, что-то вроде

 public class ArrayOfFoo {
     Object [] ary;  // ctor left as exercise

     public void set(int index, Foo value){
         ary[index] = (Object) value; // cast strictly not needed, any Foo is an Object
     }
     public void get(int index){
         return (Foo) ary[index];     // cast needed, not every Object is a Foo
     }
 }

Похоже, кодовая база у вас не построена для этого соглашения; если вы пишете новый код, нет причин, по которым вы не можете начать. В противном случае ваше соглашение не является плохим, но легко забыть актерский состав, а затем искать, чтобы выяснить, почему вы получаете исключение для плохого актера. Мягко лучше прибегнуть к некоторому варианту на венгерской нотации или соглашению Smalltalk 'aVariable', кодируя тип в именах, чтобы вы использовали

 Object fooAry = new Object[aZillion];

 fooAry[42] = new Foo();
 Foo aFoo = fooAry[42];
1 голос
/ 28 мая 2011

Я бы рекомендовал писать тесты. По разным причинам:

  • Вы все равно должны писать тесты!
  • Вы можете очень легко определить тип члена коллекции, чтобы все пути кода добавляли правильные типы в коллекцию
  • Вы можете использовать тест для написания кода, который служит «примером» того, как правильно использовать коллекцию
1 голос
/ 28 мая 2011

Используйте прозрачные идентификаторы переменных, такие как jobList, actionList или dictionaryMap. Если вас интересует тип объектов, которые они содержат, вы можете даже договориться, чтобы идентификатор коллекции всегда указывал, какой тип объектов он содержит.

Встроенные комментарии на самом деле не такая идея. Когда я перенес проект 1.5 обратно на 1.4, я сделал это (вместо удаления параметров типа). Это сработало довольно хорошо.

0 голосов
/ 28 мая 2011

Если вам просто нужна бинарная совместимость до 1.4, вы можете рассмотреть возможность использования инструмента, чтобы понизить файлы классов до 1.4 и, таким образом, начать разработку в 1.6 или 1.7 прямо сейчас. Вы, конечно, должны избегать любого API, которого не было в 1.4 (к сожалению, вы не можете скомпилировать код с универсальными элементами непосредственно из jar-файлов 1.4, поскольку они не объявляют универсальные типы). Байт-код все тот же (по крайней мере, с 1.6, я точно не знаю, с 1.7). Один бесплатный инструмент, который может сделать трюк - ProGuard . Он может делать гораздо более сложные вещи, а также может удалять все следы обобщений в файлах классов. Просто отключите запутывание и оптимизацию, если вам это не нужно. Он также предупредит вас, если в обработанном коде использовался какой-то отсутствующий API, если вы передадите ему библиотеки 1.4.

Я знаю, что это считается взломом для многих, но у нас было похожее требование, когда нам требовался код для работы на Персональной виртуальной машине Java (это по сути Java 1.1) и нескольких других экзотических виртуальных машинах, и этот подход работал довольно Что ж. Мы начали с ProGuard, а затем создали собственный инструмент для этой задачи, чтобы иметь возможность реализовать несколько обходных путей для некоторых ошибок в различных виртуальных машинах.

...