Java:Out with the Old,In with the New

And*_*NER 65 java

Java已经接近第7版了.在我看来,必须有大量的教科书和培训手册,这些教科书和培训手册基于Java的旧版本教授方法,其中所教授的方法现在将有更好的解决方案.

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

小智 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;
Run Code Online (Sandbox Code Playgroud)

public enum Suit { 
  CLUBS, 
  DIAMONDS, 
  HEARTS, 
  SPADES 
}
Run Code Online (Sandbox Code Playgroud)

  • 从来没有真正需要的. (2认同)

Eli*_*lie 45

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

编辑:

之前:

List l = someList;
Iterator i = l.getIterator();
while (i.hasNext()) {
    MyObject o = (MyObject)i.next();
}
Run Code Online (Sandbox Code Playgroud)

List<MyObject> l = someList;
for (MyObject o : l) {
    //do something
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,但问题是,在您的代码中,您不必编写它,这是较新版本Java的一个很好的功能.仅仅因为在后台没有任何改变并不意味着它不是一个好的功能. (10认同)

Dón*_*nal 37

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

  • 一些现代JIT可以告诉锁何时是线程局部的并且优化它,使StringBuffer和StringBuilder一样快......但我不记得究竟是哪个JVM做到了这一点. (3认同)
  • 出于同样的原因,ArrayList优先于Vector,HashMap优先于Hashtable. (2认同)

cd1*_*cd1 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.");
}
Run Code Online (Sandbox Code Playgroud)

Java 5:

Scanner reader = new Scanner(System.in);
String str = reader.nextLine();
reader.close();
Run Code Online (Sandbox Code Playgroud)

Java 6:

Console reader = System.console();
String str = reader.readLine();
Run Code Online (Sandbox Code Playgroud)

  • String string = System.console().readLine(); 甚至更小 (3认同)

Jul*_*ang 24

这是我看到的一个:

String.split()对比StringTokenizer.

StringTokenizer 不推荐用于新代码,但我仍然看到人们使用它.

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

  • JavaDoc说"StringTokenizer是一个遗留类,出于兼容性原因而保留,但在新代码中不鼓励使用它.建议任何寻求此功能的人都使用String的split方法或java.util.regex包." (3认同)

Jam*_*hek 24

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

看到:

java.util.Timer中

javax.swing.Timer中

java.util.concurrent中.*


dog*_*ane 21

VARARGS也很有用.

例如,您可以使用:

public int add(int... numbers){
    int sum = 0 ;
    for (int i : numbers){
        sum+=i;
    }
    return sum ;
}
Run Code Online (Sandbox Code Playgroud)

代替:

public int add(int n1, int n2, int n3, int n4) ;
Run Code Online (Sandbox Code Playgroud)

要么

public int add(List<Integer> numbers) ;
Run Code Online (Sandbox Code Playgroud)


Dón*_*nal 17

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

  • java.util.Stack也是恶魔. (2认同)

kgi*_*kis 16

格式化打印最早在JDK 1.5中引入.所以不要使用:

String str = "test " + intValue + " test " + doubleValue;
Run Code Online (Sandbox Code Playgroud)

或使用StringBuilder的等价物,

一个人可以使用

String str = String.format("test %d test %lg", intValue, doubleValue);
Run Code Online (Sandbox Code Playgroud)

后者在字符串连接和字符串构建器版本中更具可读性.我仍然发现人们很慢地采用这种风格.例如,Log4j框架不使用它,虽然我相信它会大大受益.

  • 我仍然不明白为什么他们将格式化为静态方法."test%d".format(intValue)看起来会好得多! (8认同)

Dón*_*nal 15

原语和包装类型之间的显式转换(例如,Integer to int或反之亦然),自Java 1.5以来,它通过自动装箱/拆箱自动处理.

一个例子是

Integer myInteger = 6;
int myInt = myInteger.intValue();
Run Code Online (Sandbox Code Playgroud)

可以简单地写成

Integer myInteger = 6;
int myInt = myInteger;
Run Code Online (Sandbox Code Playgroud)

但请注意NullPointerExceptions :)

  • 我认为他的意思是"之前"的例子应该说"new Integer(6)",而"after"的例子已经很好了. (2认同)

Jam*_*uis 12

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

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

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


Vin*_*nie 12

自1.5以来的一个简单更改,但在Swing API中访问JFrame的contentPane有一点不同:

myframe.getContentPane().add(mycomponent);
Run Code Online (Sandbox Code Playgroud)

myframe.add(mycomponent);
Run Code Online (Sandbox Code Playgroud)

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

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


Ogr*_*m33 11

通用集合使编码更具抗bug性.旧:

Vector stringVector = new Vector();
stringVector.add("hi");
stringVector.add(528); // oops!
stringVector.add(new Whatzit());  // Oh my, could spell trouble later on!
Run Code Online (Sandbox Code Playgroud)

新:

ArrayList<String> stringList = new ArrayList<String>();
stringList.add("hello again");
stringList.add(new Whatzit()); // Won't compile!
Run Code Online (Sandbox Code Playgroud)


小智 11

使用迭代器:

List list = getTheList();
Iterator iter = list.iterator()
while (iter.hasNext()) {
  String s = (String) iter.next();
    // .. do something
}
Run Code Online (Sandbox Code Playgroud)

或者有时会看到另一种形式:

List list = getTheList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
  String s = (String) iter.next();
  // .. do something
}
Run Code Online (Sandbox Code Playgroud)

现在全部被替换为:

List<String> list = getTheList();
for (String s : list) {
  // .. do something
}
Run Code Online (Sandbox Code Playgroud)


Bil*_*ard 11

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

import static Math.* ;
Run Code Online (Sandbox Code Playgroud)

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

  • +1.如果你在一个类中定义了一堆常量,而另一个类大量使用它们,则特别有用.当然,滥用静态导入很容易使代码变得不那么清晰(特别是对于方法调用). (3认同)

Kip*_*Kip 10

将数字转换为字符串:

String s = n + "";
Run Code Online (Sandbox Code Playgroud)

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

String s = String.valueOf(n);
Run Code Online (Sandbox Code Playgroud)


cd1*_*cd1 10

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

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);
Run Code Online (Sandbox Code Playgroud)

Java 6:

int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOf(src, src.length);
Run Code Online (Sandbox Code Playgroud)

以前,我必须显式创建一个新数组,然后将源元素复制到新数组(调用具有大量参数的方法).现在,语法更清晰,新的数组从方法返回,我不必创建它.顺便说一句,方法Arrays.copyOf有一个名为Arrays.copyOfRange的变体,它复制源数组的特定区域(非常类似于System.arraycopy).


coo*_*ird 8

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

这些天,当我看到样板for循环使用索引变量一个接一个地迭代一个数组时,它让我想要尖叫:

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

forJava 5中引入构造替换上面的代码:

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

干净,简洁,最重要的是,它为代码赋予了意义,而不是展示如何做某事.

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

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


Jon*_*nik 7

varargs相关; 实用方法 Arrays.asList(),从Java 5开始,采用varargs参数非常有用.

我经常发现自己简化了类似的东西

List<String> items = new ArrayList<String>();
items.add("one");
items.add("two");
items.add("three");
handleItems(items);
Run Code Online (Sandbox Code Playgroud)

通过使用

handleItems(Arrays.asList("one", "two", "three"));
Run Code Online (Sandbox Code Playgroud)


Dan*_*ski 6

注释

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

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


Kje*_*ard 5

更改JUnit 3样式测试:

class Test extends TestCase {
    public void testYadaYada() { ... }
}
Run Code Online (Sandbox Code Playgroud)

到JUnit 4式测试:

class Test {
   @Test public void yadaYada() { ... }
}
Run Code Online (Sandbox Code Playgroud)

  • 这真的有帮助吗? (3认同)
  • 您的测试用例现在可以扩展被测试的类以轻松测试受保护的方法. (2认同)