Java:Out with the Old,In with the New

时间:2008-11-03 15:15:23

标签: java

Java即将推出版本7.在我看来,必须有大量的教科书和培训手册,这些教科书和培训手册都是基于Java的旧版本教授方法,其中教授的方法现在有更好的解决方案。

什么样的样板代码情况,特别是那些你看到人们通过习惯实现的情况,你发现自己重构利用最新版本的Java?

30 个答案:

答案 0 :(得分:70)

枚举。替换

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 
}

答案 1 :(得分:45)

泛型,不再需要创建迭代器来遍历集合中的所有元素。新版本更好,更易于使用,更易于理解。

编辑:

在:

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
}

答案 2 :(得分:37)

使用StringBuffer类型的局部变量来执行字符串连接。除非需要同步,否则现在建议使用StringBuilder,因为此类提供了更好的性能(可能是因为它不同步)。

答案 3 :(得分:35)

从标准输入读取字符串:

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();

答案 4 :(得分:24)

这是我看到的一个:

String.split()StringTokenizer

StringTokenizer不建议用于新代码,但我仍然看到人们使用它。

至于兼容性,Sun努力让Java向后兼容。这部分地解释了为什么泛型如此复杂。弃用也应该有助于简化从旧代码到新代码的转换。

答案 5 :(得分:24)

使用Thread而不是Thread的许多其他替代品的旧代码......现在,我运行的代码中很少有代码仍然需要使用原始线程。抽象级别可以提供更好的服务,特别是Callable / Futures / Executors

请参阅:

java.util.Timer

javax.swing.Timer

java.util.concurrent.*

答案 6 :(得分:21)

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) ;

答案 7 :(得分:17)

使用Vector类型的局部变量来保存对象列表。除非需要同步,否则现在建议使用List实现,例如ArrayList,因为此类提供了更好的性能(因为它是不同步的)。

答案 8 :(得分:16)

格式化打印是在JDK 1.5中引入的。所以不要使用:

String str = "test " + intValue + " test " + doubleValue;

或使用StringBuilder的等效文件,

可以使用

String str = String.format("test %d test %lg", intValue, doubleValue);

后者更易读,无论是字符串连接还是字符串构建器版本。我仍然发现人们很慢地采用这种风格。例如,Log4j框架不使用它,虽然我相信它会大大受益。

答案 9 :(得分:15)

原语和包装类型之间的显式转换(例如,Integer转换为int,反之亦然),自Java 1.5以来,自动装箱/取消装箱会自动处理。

一个例子是

Integer myInteger = 6;
int myInt = myInteger.intValue();

可以简单地写成

Integer myInteger = 6;
int myInt = myInteger;

但请注意NullPointerExceptions:)

答案 10 :(得分:12)

Q1:嗯,最明显的情况是在泛型/类型特定的集合中。另一个立即浮现在脑海中的是改进的循环,我觉得它看起来更清晰,更容易理解。

第二季度:总的来说,我一直在将JVM与我的应用程序一起捆绑在面向客户的应用程序中。这使我们可以使用新的语言功能,而不必担心JVM不兼容。

如果我没有捆绑JRE,出于兼容性原因,我可能会坚持使用1.4。

答案 11 :(得分:12)

自1.5以来的一个简单更改,但在Swing API访问JFrame的contentPane时产生了一些小的差异:

myframe.getContentPane().add(mycomponent);

变为

myframe.add(mycomponent);

当然,Enums的引入改变了许多过去使用常量的应用程序的行为方式。

String.format()极大地改进了字符串操作,而三元if语句在使代码更易于阅读方面非常有用。

答案 12 :(得分:11)

通用集合使编码更具抗bug性。 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!

答案 13 :(得分:11)

使用迭代器:

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
}

答案 14 :(得分:11)

虽然我承认静态导入很容易被滥用,但我喜欢使用

import static Math.* ;

在使用大量数学函数的类中。它确实可以降低代码的冗长程度。但是,我不建议将它用于鲜为人知的图书馆,因为这会导致混淆。

答案 15 :(得分:10)

将现有数组复制到新数组:

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)。

答案 16 :(得分:10)

将数字转换为字符串:

String s = n + "";

在这种情况下,我认为一直有更好的方法:

String s = String.valueOf(n);

答案 17 :(得分:8)

新的for - 迭代数组和集合的每个构造对我来说是最大的。

这些天,当我看到样板for循环使用索引变量逐个遍历数组时,它让我想要尖叫:

// AGGHHH!!!
int[] array = new int[] {0, 1, 2, 3, 4};
for (int i = 0; i < array.length; i++)
{
    // Do something...
}

for construct introduced in Java 5替换上述内容:

// Nice and clean.    
int[] array = new int[] {0, 1, 2, 3, 4};
for (int n : array)
{
    // Do something...
}

干净,简洁,最重要的是,它为代码提供含义,而不是显示如何做某事。

显然,代码有意义迭代集合,而不是旧的for循环说如何迭代数组。

此外,由于每个元素都独立于其他元素进行处理,因此可以允许将来优化并行处理,而无需对代码进行更改。 (当然是猜测。)

答案 18 :(得分:7)

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"));

答案 19 :(得分:6)

注解

我不知道到目前为止还没有人提到它,但很多框架都依赖于注释,例如SpringHibernate.今天通常不赞成使用xml配置文件来支持代码中的注释(尽管这意味着在从配置转向元代码时失去灵活性,但通常是正确的选择。最好的例子是EJB 2(和更早版本)与EJB 3.0相比以及如何通过注释简化EJB的编程。

我发现注释与AspectJ或Spring AOP等一些AOP工具结合使用也非常有用。这种组合可以非常强大。

答案 20 :(得分:5)

更改JUnit 3样式测试:

class Test extends TestCase {
    public void testYadaYada() { ... }
}

到JUnit 4式测试:

class Test {
   @Test public void yadaYada() { ... }
}

答案 21 :(得分:4)

改进的单身人士模式。从技术上讲,这些都包含在流行的答案枚举中,但它是一个重要的子类别。

public enum Singleton {
    INSTANCE;

    public void someMethod() {
        ...
    }
}

更清洁,更安全
public class Singleton {
    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {
        ...
    }

    public void someMethod() {
        ...
    }
}

答案 22 :(得分:3)

好的,现在轮到我了。

我不建议这些变化的90%。

并不是将它们与新代码一起使用并不是一个好主意,但是将现有代码更改为for循环更改为for循环只是浪费时间和破坏某些东西的机会。 (IIWDFWI)如果有效,请不要修复它!

如果您是一家真正的开发公司,那么这项变更现在可以进行代码审查,测试和调试。

如果有人无缘无故地做这种重构会导致任何类型的问题,我就不会给他们任何结果。

另一方面,如果您正在使用代码并更改该行的内容,请随时清理它。

此外,“性能”名称中的所有建议确实需要了解优化规律。用两个词来说,不要!永远! (谷歌“如果你不相信我的优化规则”。

答案 23 :(得分:3)

如果您对源代码树所做的一切都是如此,我会对这些行进行重构时保持警惕。到目前为止,这些示例似乎并不仅仅是改变任何工作代码库的原因,但是如果您要添加新功能,则应该利用所有新功能。

在一天结束时,这些示例并没有真正删除锅炉板代码,他们只是使用更易管理的新JDK构造来制作漂亮的锅炉板代码

使代码优雅的大多数方法都不在JDK中。

答案 24 :(得分:3)

转换类以使用泛型,从而避免不必要的强制转换。

答案 25 :(得分:3)

使用Swing的新DefaultRowSorter对表进行排序,而不是从头开始自己滚动。

答案 26 :(得分:2)

Java的新版本很少破坏现有代码,所以只留下旧代码并专注于新功能如何让您的生活更轻松。

如果你只留下旧代码,那么使用新功能编写新代码并不是那么可怕。

答案 27 :(得分:1)

使用Vector代替新的集合。

使用类而不是枚举

 public class Enum
  {
      public static final Enum FOO = new Enum();
      public static final Enum BAR = new Enum();
  }

使用Thread而不是新的java.util.concurrency包。

Using marker interfaces instead of annotations

答案 28 :(得分:1)

字符串比较,我见过的老派Java程序员会这样做:

String s1 = "...", s2 = "...";

if (s1.intern() == s2.intern()) {
    ....
}

(据性能原因)

而现在大多数人都这样做:

String s1 = "...", s2 = "...";

if (s1.equals(s2)) {
    ....
}

答案 29 :(得分:0)

值得注意的是,Java 5.0已经出现了五年,从那以后只有很小的变化。您必须处理非常旧的代码才能重构它。