Ответ 1
Перечисления. Замена
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
}
Java близится к версии 7. Мне приходит в голову, что должно быть много учебников и учебных пособий, которые начинают использовать методы обучения, основанные на более старых версиях Java, где методы обучения будут иметь гораздо лучшие решения.
Каковы некоторые ситуации с шаблоном кода, особенно те, которые вы видите, люди реализуют с помощью привычки, что вы обнаружите, что рефакторинг используется для использования последних версий Java?
Перечисления. Замена
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
}
Generics и больше не нужно создавать итератор для прохождения всех элементов в коллекции. Новая версия намного лучше, проще в использовании и понятна.
EDIT:
До:
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
}
Использование локальных переменных типа StringBuffer
для выполнения конкатенации строк. Если не требуется синхронизация, теперь рекомендуется использовать StringBuilder
, потому что этот класс обеспечивает лучшую производительность (предположительно потому, что он несинхронизирован).
чтение строки со стандартного ввода:
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.split()
по сравнению с StringTokenizer
.
StringTokenizer
не рекомендуется для нового кода, но я все еще вижу, как люди его используют.
Что касается совместимости, Sun прилагает огромные усилия, чтобы Java была совместима с предыдущим и предыдущим. Это частично объясняет, почему дженерики настолько сложны. Предполагается также, что устаревание облегчит переход от старого к новому.
Старый код, использующий Thread вместо многих других альтернатив Thread... в наши дни, очень мало кода, который я запускаю, по-прежнему нужно использовать поток raw. Они лучше обслуживались бы уровнем абстракции, особенно Callable/Фьючерсы/Executors.
См:
Также могут быть полезны 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) ;
Использование локальных переменных типа Vector для хранения списка объектов. Если синхронизация не требуется, теперь рекомендуется использовать реализацию List, такую как ArrayList, потому что этот класс обеспечивает лучшую производительность (поскольку он несинхронизирован).
Форматированная печать была введена уже в JDK 1.5. Поэтому вместо использования:
String str = "test " + intValue + " test " + doubleValue;
или эквивалент с помощью StringBuilder,
можно использовать
String str = String.format("test %d test %lg", intValue, doubleValue);
Последнее гораздо читаемо, как из конкатенации строк, так и из версий строковых построителей. Тем не менее я считаю, что люди принимают этот стиль очень медленно. Например, система Log4j не использует это, хотя я считаю, что это было бы очень полезно для этого.
Явное преобразование между примитивными и оболочными типами (например, Integer to int или наоборот), которое автоматически берется с помощью autoboxing/unboxing с Java 1.5.
Примером является
Integer myInteger = 6;
int myInt = myInteger.intValue();
Можно просто написать как
Integer myInteger = 6;
int myInt = myInteger;
Но обратите внимание на NullPointerExceptions:)
Q1: Ну, наиболее очевидные ситуации встречаются в коллекциях generics/type specific. Другой, который сразу же приходит на ум, - это улучшенный цикл, который, как мне кажется, выглядит более чистым и понятным.
Q2: В общем, я связывал JVM вместе с моим приложением для приложений, ориентированных на клиента. Это позволяет нам использовать новые языковые функции, не беспокоясь о несовместимости JVM.
Если бы я не связывал JRE, я бы, вероятно, придерживался 1.4 по соображениям совместимости.
Простое изменение с 1.5, но делает небольшую разницу - в Swing API, доступ к contentPane JFrame:
myframe.getContentPane().add(mycomponent);
становится
myframe.add(mycomponent);
И, конечно же, введение Enums изменило то, как многие приложения, в которых раньше использовали константы.
String.format() значительно улучшила манипуляции с строками, и оператор trernary if весьма полезен для упрощения чтения кода.
Общие коллекции делают кодирование намного более устойчивым к ошибкам. OLD:
Vector stringVector = new Vector();
stringVector.add("hi");
stringVector.add(528); // oops!
stringVector.add(new Whatzit()); // Oh my, could spell trouble later on!
NEW:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("hello again");
stringList.add(new Whatzit()); // Won't compile!
Использование Iterator:
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
}
Хотя я признаю, что статический импорт можно легко переоценить, мне нравится использовать
import static Math.* ;
в классах, которые используют множество математических функций. Это может действительно уменьшить многословие вашего кода. Однако я бы не рекомендовал его для менее известных библиотек, поскольку это может привести к путанице.
Преобразование числа в строку:
String s = n + "";
В этом случае я думаю, что всегда был лучший способ сделать это:
String s = String.valueOf(n);
копирование существующего массива в новый массив:
pre-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).
Новая конструкция 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
, говорящий о том, как перебирать массив.
Кроме того, поскольку каждый элемент обрабатывается независимо от других элементов, он может предусматривать будущую оптимизацию для параллельной обработки без необходимости внесения изменений в код. (Разумеется, это просто спекуляция.)
Связано с 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"));
Аннотация
Интересно, что никто не упоминал об этом до сих пор, но многие фреймворки полагаются на аннотации, например Spring и Hibernate. Сегодня для описания файлов конфигурации xml часто используются аннотации кода (хотя это означает, что вы теряете гибкость при переходе от конфигурации к метакоду, но часто правильный выбор). Лучшим примером является EJB 2 (и старше) по сравнению с EJB 3.0 и как упрощение программирования EJB благодаря аннотациям.
Я считаю, что аннотации также очень полезны в сочетании с некоторыми инструментами AOP, такими как AspectJ или Spring AOP. Такая комбинация может быть очень сильной.
Изменение тестов JUnit 3-стиля:
class Test extends TestCase {
public void testYadaYada() { ... }
}
для тестов JUnit 4-стиля:
class Test {
@Test public void yadaYada() { ... }
}
Улучшенные одноэлементные паттерны. Технически они охватываются популярными ответами, но это значимая подкатегория.
public enum Singleton {
INSTANCE;
public void someMethod() {
...
}
}
чище и безопаснее, чем
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
...
}
public void someMethod() {
...
}
}
Преобразование классов в использование дженериков, что позволяет избежать ситуаций с ненужными приведениями.
Я немного опасаюсь рефакторировать эти строки, если это все, что вы делаете с вашим исходным деревом. Примеры до сих пор не кажутся одними причинами для изменения любой рабочей базы кода, но, возможно, если вы добавляете новую функциональность, вы должны использовать все новые вещи.
В конце дня, эти примеры на самом деле не снимают код плиты котла, они просто используют более управляемые конструкции новых JDK для делают приятный код котельной плиты strong > .
Большинство способов сделать ваш код элегантным не в JDK.
Хорошо, теперь моя очередь кричать.
Я не рекомендую 90% этих изменений.
Не то, чтобы это не очень хорошая идея использовать их с новым кодом, но взломать существующий код, чтобы изменить цикл for на цикл for (:) - это просто пустая трата времени и шанс что-то сломать. (IIWDFWI) Если это работает, не исправляйте это!
Если вы находитесь в реальной компании-разработчике, это изменение теперь становится чем-то вроде проверки кода, тестирования и, возможно, отладки.
Если кто-то, кто делает такой рефакторинг без причины, вызвал проблему ЛЮБОГО рода, я бы не дал им окончательного дерьма.
С другой стороны, если вы все равно в коде и меняете материал на этой линии, не стесняйтесь его очищать.
Кроме того, всем предложениям от имени "Производительность" действительно нужно узнать о законах оптимизации. В двух словах: "Не делай! Когда-либо! (Google" Правила оптимизации, если вы мне не верите").
Использование Swing new DefaultRowSorter
для сортировки таблиц по сравнению с переносом вашего собственного с нуля.
Новая версия Java редко нарушает существующий код, поэтому просто оставляйте только старый код и сосредоточьтесь на том, как новая функция упрощает вашу жизнь.
Если вы просто оставите старый код один, то писать новый код с помощью новых функций не так страшно.
Сравнение строк, действительно старые школьные Java-программисты, с которыми я встречался, будут делать:
String s1 = "...", s2 = "...";
if (s1.intern() == s2.intern()) {
....
}
(предположительно по соображениям производительности)
В то время как в наши дни большинство людей просто делают:
String s1 = "...", s2 = "...";
if (s1.equals(s2)) {
....
}
Использование Vector вместо новых коллекций.
Использование классов вместо перечислений
public class Enum
{
public static final Enum FOO = new Enum();
public static final Enum BAR = new Enum();
}
Использование Thread вместо нового пакета java.util.concurrency.
Стоит отметить, что Java 5.0 существует уже пять лет, и с тех пор произошли незначительные изменения. Вам нужно будет работать с очень старым кодом, чтобы все еще рефакторировать его.