Java приближается к версии 7. Мне пришло в голову, что должно быть много учебников и учебных пособий, которые преподают методы, основанные на более старых версиях Java, где эти методы теперь имеют гораздо лучшие решения.
Какие ситуации с шаблонным кодом, особенно те, которые, как вы видите, люди реализуют по привычке, вы занимаетесь рефакторингом для использования последних версий Java?
Как может человек с репутацией 402 (на данный момент) иметь вопрос на 550 наград? Я знаю, что вы получаете 50 от системы наград, но даже после этого у него будет -98 репутация. Или это отнимает у вас очки репутации, когда вы назначаете награду?
@Bratch - Может быть, у них была подработка на Уолл-стрит, где получение награды сверх их кошелька является нормой.
@Bratch и Random Echo: награда списывается немедленно, а не после принятия ответа. Проверьте его историю повторений.
Глядя на этот список, удручает ... Я не помнил, чтобы Java была настолько плохой, но, глядя на новые функции, как на то, чего не хватало, я не могу поверить, что использовал Java ... у нее не было перечислений или varargs , или приличные дженерики, или, или, ...




Generics и больше не нужно создавать итератор для просмотра всех элементов в коллекции. Новая версия намного лучше, проще в использовании и понятнее.
Обновлено:
До:
List l = someList;
Iterator i = l.getIterator();
while (i.hasNext()) {
MyObject o = (MyObject)i.next();
}
После
List<MyObject> l = someList;
for (MyObject o : l) {
//do something
}
Базовый механизм нового цикла for по-прежнему создает итератор, вам просто не нужно писать для него шаблонный код.
Я как раз собирался это сказать, ск
да, но дело в том, что в вашем коде вам НЕ нужно его писать, и это хорошая особенность новых версий Java. То, что в фоновом режиме ничего не изменилось, не означает, что это плохая функция.
Ах, есть еще тот факт, что обобщения обеспечивают безопасность типов для коллекций. По этой причине, на мой взгляд, рефакторинг кода 1.4 до 1.5 имеет огромное значение для читабельности.
Вы упомянули Generics, но в вашем примере цикла по-прежнему используется Object. Тск Тск. :)
Q1: Что ж, наиболее очевидные ситуации находятся в коллекциях для конкретных типов / типов. Еще один момент, который сразу приходит в голову, - это улучшенный цикл for, который, как мне кажется, выглядит намного чище и проще для понимания.
Q2: Как правило, я объединяю JVM вместе со своим приложением для приложений, ориентированных на клиентов. Это позволяет нам использовать новые языковые функции, не беспокоясь о несовместимости JVM.
Если бы я не собирал JRE, я бы, вероятно, придерживался 1.4 из соображений совместимости.
старайтесь публиковать по одному ответу за раз (чтобы каждый можно было оценить индивидуально)
Я не уверен, что вы имеете в виду...?
Он имел в виду, что вам следовало разделить этот ответ на два отдельных ответа.
Преобразование числа в строку:
String s = n + "";
В этом случае я думаю, что всегда был лучший способ сделать это:
String s = String.valueOf(n);
String.valueOf (n) решает эту последнюю проблему.
Строка s = n + ""; это плохая привычка, потому что она всегда создает новый объект. valueOf в этом умнее.
Вы правы, рано утром совсем забыл про String.valueOf (n). Я его обновил.
valueOf: начиная с версии 1.3
Не забывайте статический метод Integer.toString (int, int). Это дает вам строковое представление первого параметра в базе, указанной вторым параметром.
Это одна из тех вещей, которые настолько распространены, что я бы хотел, чтобы компилятор справился с этим за вас.
@chriskes это так, просто используйте s = n + ""! Пока кто-то не сможет продемонстрировать производственный код, в котором эти дурацкие небольшие настройки действительно ускорят что-то, я буду придерживаться принципа не перехитрить компилятор, пытаясь понять, как он реализует эти вещи (которые меняют каждый выпуск)
Простое изменение с версии 1.5, но имеет небольшое различие - в Swing API, обращающемся к contentPane JFrame:
myframe.getContentPane().add(mycomponent);
становится
myframe.add(mycomponent);
И, конечно же, введение Enums изменило поведение многих приложений, которые в прошлом использовали константы.
String.format () значительно улучшил манипуляции со строками, а тернарный оператор if весьма полезен для облегчения чтения кода.
Если я правильно помню, myframe.add (...) использовался для вывода предупреждающего сообщения на stderr.
Нет, в pre-1.5 JRE выдает ошибку во время выполнения: исключение в потоке "main" java.lang.Error: не используйте javax.swing.JFrame.add () используйте javax.swing.JFrame.getContentPane () .add () вместо
Enums. Замена
public static final int CLUBS = 0;
public static final int DIAMONDS = 1;
public static final int HEARTS = 2;
public static final int SPADES = 3;
с
public enum Suit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES
}
новый материал намного красивее. ;-)
Вот один, который я вижу:
String.split() против StringTokenizer.
StringTokenizer не рекомендуется для нового кода, но я все еще вижу, что люди его используют.
Что касается совместимости, Sun прилагает огромные усилия для обеспечения обратной и прямой совместимости с Java. Это частично объясняет, почему дженерики такие сложные. Предполагается, что устаревание также поможет облегчить переход от старого кода к новому.
:( Не слышал, что StringTokenizer больше не рекомендуется. Мне нравится StringTokenizer! Отлично подходит для декодирования переключаемых входов и сложных операторов. Вещи, где, кажется, было бы очень сложно сделать с split ().
@Brian Knoblauch Я думаю, что String.split () должен заменить 80% -ный случай использования StringTokenizer с одним токеном и флагами по умолчанию. Вы все еще можете использовать StringTokenizer в более сложных ситуациях, как вы упомянули.
В JavaDoc говорится: «StringTokenizer - это устаревший класс, который сохранен по соображениям совместимости, хотя его использование не рекомендуется в новом коде. Рекомендуется, чтобы любой, кто ищет эту функциональность, использовал вместо этого метод разделения String или пакет java.util.regex».
@Brian Split и минимальный цикл должен быть близок к StringTokenizer, но я согласен. Также я презираю регулярные выражения, которые, кажется, требуют разделения. Я также не мог понять, как разделить, чтобы вернуть токены или нет (вероятно, это часть синтаксиса RE, с которой я не хочу иметь дело).
@Bill: Нет, они это упустили - на других языках вы можете вернуть разделители, заключив регулярное выражение в круглые скобки, но не Java. Не могу сказать, что виню их, учитывая, сколько людей даже не понимают регулярные выражения использует.
Использование локальных переменных типа StringBuffer для конкатенации строк. Если синхронизация не требуется, теперь рекомендуется использовать StringBuilder, потому что этот класс предлагает лучшую производительность (предположительно, потому что он не синхронизирован).
ArrayList предпочтительнее Vector, а HashMap - Hashtable по той же причине.
Некоторые современные JIT могут определить, когда блокировка является локальной для потока, и оптимизировать ее, делая StringBuffer таким же быстрым, как StringBuilder ... но я не совсем помню, какие именно JVM сделали это.
это называется анализом побега - и он должен быть частью jre6
Использование локальных переменных типа Vector для хранения списка объектов. Если синхронизация не требуется, теперь рекомендуется использовать реализацию списка, такую как ArrayList, потому что этот класс обеспечивает лучшую производительность (поскольку он не синхронизирован).
Это что-то новенькое? Я думал, что так было всегда.
Зависит от того, как вы определяете «новый». Я застрял в написании кода Java 1.1 (чтобы мы могли поддерживать людей, которые отказываются обновляться с MS JVM), а несинхронизированных коллекций тогда не существовало.
Это не совсем так. Вектор - это тип данных, явно отличный от ArrayList, т. Е. посмотрите на метод setSize. Тем не менее, в большинстве случаев векторный тип не нужен.
Это другой класс (очевидно), но оба они являются реализациями List. Моя точка зрения заключалась в том, что часто часто используется вектор, где вместо него может / должна использоваться другая реализация списка.
Извините - плохо сформулировано с моей стороны. Я полностью согласен с вашей точкой зрения. Просто пытаюсь указать, что Vector - это массив с изменяемым размером (например, STL), а ArrayList - нет. В таких случаях ArrayList работать не будет. Это улавливает множество преобразований C++, потому что им сообщается ArrayList == Vector.
java.util.Stack - это тоже дьявол.
Явное преобразование между примитивным типом и типом оболочки (например, Integer в int или наоборот), которое выполняется автоматически с помощью автобокса / распаковки, начиная с Java 1.5.
Примером является
Integer myInteger = 6;
int myInt = myInteger.intValue();
Можно просто записать как
Integer myInteger = 6;
int myInt = myInteger;
Но остерегайтесь NullPointerExceptions :)
Конечно, это должно быть: Integer myInteger = new Integer (6); :)
Нет, совершенно законно присвоить целочисленное значение буквальное значение. Ваш код тоже подойдет, но для краткости я предпочитаю использовать литералы.
Я думаю, он имеет в виду, что пример «до» должен сказать «новое целое число (6)», а пример «после» уже подходит.
Также имейте в виду, что упакованное int не равно упакованному long, даже если оно имеет такое же значение.
Новая версия Java редко нарушает существующий код, поэтому просто оставьте старый код в покое и сосредоточьтесь на том, как новая функция облегчает вашу жизнь.
Если вы просто оставите старый код в покое, то писать новый код с использованием новых функций не так страшно.
Это нормально, если в вашем старом коде нет ошибок и не требуется никакого обслуживания!
Весь код, который каждый когда-либо создает, - это устаревший код. Что хорошие бойскауты делают с лагерем? :)
Я вроде как согласен с этим. Если я занимаюсь исправлением ошибок или добавлением функциональности, я тоже буду реорганизовывать его. Но я никогда не буду реорганизовывать что-то, что все еще работает, просто для использования новых функций.
Большинство из нас, вероятно, недостаточно удачливы, чтобы «оставить старый код в покое». И когда вы прикоснетесь к нему, было бы глупо не использовать новые функции (если, конечно, этот старый код не должен работать в 1.4 или что-то в этом роде).
Общие коллекции делают кодирование более устойчивым к ошибкам. СТАРЫЙ:
Vector stringVector = new Vector();
stringVector.add("hi");
stringVector.add(528); // oops!
stringVector.add(new Whatzit()); // Oh my, could spell trouble later on!
НОВЫЙ:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("hello again");
stringList.add(new Whatzit()); // Won't compile!
Старый код, использующий Thread вместо многих других альтернатив Thread ... в наши дни очень небольшая часть кода, с которым я сталкиваюсь, по-прежнему требует использования необработанного потока. Их лучше обслуживать уровень абстракции, в частности Вызываемый / Фьючерсы / Исполнители.
Видеть:
Используя итератор:
List list = getTheList();
Iterator iter = list.iterator()
while (iter.hasNext()) {
String s = (String) iter.next();
// .. do something
}
Или иногда можно увидеть альтернативную форму:
List list = getTheList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
String s = (String) iter.next();
// .. do something
}
Теперь все заменено на:
List<String> list = getTheList();
for (String s : list) {
// .. do something
}
Строковые сравнения, действительно старые программисты Java, которых я встречал, сделали бы:
String s1 = "...", s2 = "...";
if (s1.intern() == s2.intern()) {
....
}
(Предположительно по соображениям производительности)
В то время как в наши дни большинство людей просто делают:
String s1 = "...", s2 = "...";
if (s1.equals(s2)) {
....
}
intern - это память, а не скорость, действительно, стажер сделает ваш код медленнее, поскольку это дорогостоящая операция (если они не исправили это недавно ... на самом деле я скоро узнаю, что собираюсь сделать что-то, что проверит это)
Кроме того, в этом случае s1 и s2 являются буквальными строками, поэтому они автоматически интернируются в соответствии со спецификацией. Итак, первый пример на самом деле является пустой тратой набора текста.
С самого начала правильным способом сравнения строк на предмет равенства почти всегда было equals (). Что делает intern (), так это берет String и возвращает ссылку на каноническую String в пуле, поддерживаемом классом String. Все литералы также добавляются в этот пул. Интернированные строки и литералы может сравниваются на идентичность с == на высокой скорости. При тщательной оптимизации большого сервера я обнаружил два места, где intern () приводил к заметному увеличению производительности. Однако в 99,99% всех случаев используйте equals (), чтобы предотвратить ошибки и уменьшить литеральный пул.
VARARGS тоже могут быть полезны.
Например, вы можете использовать:
public int add(int... numbers){
int sum = 0 ;
for (int i : numbers){
sum+=i;
}
return sum ;
}
вместо:
public int add(int n1, int n2, int n3, int n4) ;
или же
public int add(List<Integer> numbers) ;
Я обнаружил, что varargs очень полезны. Трудно представить, что мы делали раньше. По-прежнему существует множество устаревших API с перегруженными методами с 1 аргументом, 2 аргументами, 3 аргументами, 4 аргументами и аргументами object []. вздох.
Я не знал, что это было в java! было добавлено в 5 или 6? Я не делал много java, кроме академической работы и j2me, основанного на 1.4 :(
Использование вектора вместо новых коллекций.
Использование классов вместо перечислений
public class Enum
{
public static final Enum FOO = new Enum();
public static final Enum BAR = new Enum();
}
Использование Thread вместо нового пакета java.util.concurrency.
Изменение тестов в стиле JUnit 3:
class Test extends TestCase {
public void testYadaYada() { ... }
}
в тесты в стиле JUnit 4:
class Test {
@Test public void yadaYada() { ... }
}
Это действительно хоть чему-нибудь помогает?
Да, было бы неплохо перечислить преимущества. Из примера не совсем ясно, почему стиль JUnit 4 лучше.
@Test (ожидается = ExpectedException.class)
Теперь ваш тестовый пример может расширить тестируемый класс, чтобы легко тестировать защищенные методы.
@Mark: Для тех, кто пользуется общей идиомой наличия тестового класса в той же упаковке в качестве тестируемого кода (но с другой структурой каталога), в этом нет ничего нового.
Хотя я признаю, что статическим импортом можно легко злоупотреблять, мне нравится использовать
import static Math.* ;
в классах, которые используют много математических функций. Это действительно может уменьшить многословность вашего кода. Однако я бы не рекомендовал его для менее известных библиотек, поскольку это может привести к путанице.
+1. Это особенно полезно, если у вас есть несколько констант, определенных в одном классе, а другой класс активно их использует. Конечно, неправильное использование статического импорта может легко сделать код менее понятным (особенно для вызовов методов).
Новая конструкция for-each для перебора массивов и коллекций является для меня самой большой.
В наши дни, когда я вижу шаблонный цикл for для последовательного перебора массива с использованием индексной переменной, мне хочется кричать:
// AGGHHH!!!
int[] array = new int[] {0, 1, 2, 3, 4};
for (int i = 0; i < array.length; i++)
{
// Do something...
}
Замена вышеуказанного на Конструкция for, представленная в Java 5:
// Nice and clean.
int[] array = new int[] {0, 1, 2, 3, 4};
for (int n : array)
{
// Do something...
}
Чистый, лаконичный и, что самое главное, он дает коду смысл, а не показывает, что как что-то делает.
Ясно, что код имеет смысл перебирать коллекцию, а не старый цикл for, говорящий, как перебирать массив.
Кроме того, поскольку каждый элемент обрабатывается независимо от других элементов, это может позволить будущую оптимизацию для параллельной обработки без необходимости вносить изменения в код. (Конечно, это просто предположение.)
Форматированная печать была введена только в JDK 1.5. Поэтому вместо использования:
String str = "test " + intValue + " test " + doubleValue;
или эквивалент с использованием StringBuilder,
можно использовать
String str = String.format("test %d test %lg", intValue, doubleValue);
Последний вариант гораздо более читабелен как в версии с конкатенацией строк, так и в версиях построителя строк. Тем не менее, я считаю, что люди очень медленно перенимают этот стиль. Например, фреймворк Log4j не использует это, хотя я считаю, что это было бы очень полезно.
Я до сих пор не понимаю, почему они сделали форматирование статическим методом. "test% d" .format (intValue) выглядел бы намного лучше!
Не вижу, чтобы это использовалось слишком часто, скорее всего, из-за силы привычки. Для более современного ведения журнала вы можете посмотреть журнал, который очень хорош и обратно совместим с log4j.
+1 на log4j - мне не хватает этой функции, которая существует в log4net.
Другой вариант ведения журнала - Simple Logging Facade для Java (SLF4J), он поддерживает varargs.
+1. В сочетании с изящным действием намерения IntelliJ IDEA «заменить + вызовом String.format ()» теперь быстро и легко сделать подробные устаревшие операторы ведения журнала более понятными для много!
Преобразование классов для использования универсальных типов, что позволяет избежать ситуаций с ненужным приведением типов.
Я немного опасаюсь проводить рефакторинг в этом направлении, если это все, что вы делаете со своим исходным деревом. Примеры пока не кажутся единственными причинами для изменения какой-либо рабочей базы кода, но, возможно, если вы добавляете новые функции, вам следует воспользоваться всеми новыми вещами.
В конце концов, этот пример на самом деле не удаляет код плиты котла., они просто используют более управляемые конструкции новых JDK для сделать красивый код котельной плиты.
Большинство способов сделать ваш код элегантным не входят в JDK.
Хорошо, теперь моя очередь кричать на меня.
Я не рекомендую 90% этих изменений.
Это не значит, что использовать их с новым кодом - плохая идея, но взлом существующего кода для изменения цикла for на цикл for (:) - это просто пустая трата времени и шанс что-то сломать. (IIWDFWI) Если работает, не исправляйте!
Если вы работаете в реальной компании-разработчике, это изменение теперь требует проверки кода, тестирования и, возможно, отладки.
Если кто-то, выполняющий такого рода рефакторинг без всякой причины, вызвал ЛЮБУЮ проблему, я бы не стал им насрать.
С другой стороны, если вы находитесь в коде и все равно меняете что-то в этой строке, не стесняйтесь ее очищать.
Кроме того, все предложения в названии «Производительность» действительно нужно узнать о законах оптимизации. В двух словах: не надо! Всегда! (Погуглите "Правила оптимизации, если не верите)".
Если он работает, но некрасиво, и вы не исправляете его, когда у вас есть время, то есть вероятность, что когда вам нужно внести изменения в код, вы будете слишком заняты, чтобы провести рефакторинг, слишком напуганы, потому что надвигается жесткий дедлайн. , и с большей вероятностью допустят ошибки, потому что вы не очистили его, когда у вас была возможность. Основная идея рефакторинга заключается в том, что он выплачивает технический долг и облегчает вам жизнь в будущем.
Что некрасиво? Я считаю уродливым дублированный код, неприятные наборы параметров в методе, классы, которые слишком хорошо знают друг друга и т. д. Традиционный цикл for на самом деле не сложен или что-то в этом роде, просто менее краток. Если он на самом деле исправляет один из «Уродливых» элементов, о которых я только что упомянул, дерзайте! Но не начинайте просто добавлять (или удалять) это. перед каждой переменной-членом, потому что вы думаете, что так или иначе менее "некрасиво"
Реализация этих рефакторингов не требует участия человека.
Относится к varargs; очень полезен служебный метод Arrays.asList (), который, начиная с Java 5, принимает параметры varargs.
Я часто замечаю, что упрощаю что-то вроде
List<String> items = new ArrayList<String>();
items.add("one");
items.add("two");
items.add("three");
handleItems(items);
используя
handleItems(Arrays.asList("one", "two", "three"));
чтение строки из стандартного ввода:
Java pre-5:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = reader.readLine();
reader.close();
}
catch (IOException e) {
System.err.println("error when closing input stream.");
}
Java 5:
Scanner reader = new Scanner(System.in);
String str = reader.nextLine();
reader.close();
Java 6:
Console reader = System.console();
String str = reader.readLine();
Невероятно, как им потребовалось так много времени, чтобы сделать такую простую вещь по-настоящему простой для программирования!
Строка string = System.console (). ReadLine (); еще более минимальный
Использование нового Swing DefaultRowSorter для сортировки таблиц вместо создания собственных с нуля.
Стоит отметить, что Java 5.0 отсутствует уже пять лет, и с тех пор в нее были внесены лишь незначительные изменения. Вам придется работать над очень старым кодом, чтобы продолжать его рефакторинг.
копирование существующего массива в новый массив:
до Java 5:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = new int[src.length];
System.arraycopy(src, 0, dest, 0, src.length);
Java 6:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOf(src, src.length);
раньше мне приходилось явно создавать новый массив, а затем копировать исходные элементы в новый массив (вызывая метод с большим количеством параметров). теперь синтаксис стал более чистым, и новый массив возвращается из метода, мне не нужно его создавать. кстати, у метода Arrays.copyOf есть вариант под названием Arrays.copyOfRange, который копирует определенную область исходного массива (очень похоже на System.arraycopy).
Старый пост, я знаю, но если вы хотите сделать точную копию массива, то clone() - самый простой способ (и был с рождения Java): int[] copy = original.clone(); Тип возврата clone для массивов ковариантен (с 1.5), поэтому вы даже кастинг не нужен. Но я согласен, что Arrays.copyOf - сладкий сладкий сахар для других операций копирования.
Аннотации
Интересно, что до сих пор об этом никто не упоминал, но многие фреймворки полагаются на аннотации, например Spring и Спящий режим.. Сегодня широко распространено устаревание файлов конфигурации xml в пользу аннотаций в коде (хотя это означает потерю гибкости при переходе от конфигурации к мета- код, но часто это правильный выбор). Лучшим примером является EJB 2 (и старше) по сравнению с EJB 3.0 и то, как программирование EJB было упрощено благодаря аннотациям.
Я считаю, что аннотации также очень полезны в сочетании с некоторыми инструментами АОП, такими как AspectJ или Spring AOP. Такое сочетание может быть очень мощным.
Улучшены одноэлементные шаблоны. Технически они относятся к популярным перечислениям ответов, но это важная подкатегория.
public enum Singleton {
INSTANCE;
public void someMethod() {
...
}
}
чище и безопаснее, чем
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
...
}
public void someMethod() {
...
}
}
Зачем открывать награду за открытый вопрос? Это не тот вопрос, на который вам следует выбирать ответ.