当前位置:  开发笔记 > 编程语言 > 正文

Java - 常见问题

如何解决《Java-常见问题》经验,为你挑选了18个好方法。

与其他平台一样,跟进这个问题似乎合乎逻辑:Java中常见的非明显错误是什么?似乎他们应该工作的事情,但不是.

我不会给出如何构建答案的指导,或者什么"太容易"被认为是一个问题,因为这就是投票的目的.

也可以看看:

Perl - 常见问题

.NET - 常见陷阱

butterchicke.. 36

"a,b,c,d,,,".split(",").length

返回4,而不是 7,因为你可能(我当然这样做)期望.split忽略返回的所有尾随空字符串.这意味着:

",,,a,b,c,d".split(",").length

返回7!为了得到我认为的"最不惊人"的行为,你需要做一些非常惊人的事情:

"a,b,c,d,,,".split(",",-1).length

得到7.



1> butterchicke..:
"a,b,c,d,,,".split(",").length

返回4,而不是 7,因为你可能(我当然这样做)期望.split忽略返回的所有尾随空字符串.这意味着:

",,,a,b,c,d".split(",").length

返回7!为了得到我认为的"最不惊人"的行为,你需要做一些非常惊人的事情:

"a,b,c,d,,,".split(",",-1).length

得到7.



2> David..:

使用==而不是.equals()- 比较对象的相等性- 对于基元,其行为完全不同.

这种疑难杂症,确保新人都昏昏沉沉的时候"foo" == "foo",但是new String("foo") != new String("foo").


有趣的是,Groovy使用'=='作为值比较而不是对象身份比较.复制粘贴时要小心!

3> extraneon..:

覆盖equals()但不覆盖hashCode()

使用地图,集合或列表时,它可能会产生意想不到的结果.


更不用说:用错误的签名覆盖`equals`.`public boolean equals(MyStuff other)...`而不是`public boolean equals(Object other)...`

4> oxbow_lakes..:

我觉得这个String.substring方法非常狡猾.这将重新使用与char[]原始字符串相同的底层数组,并使用不同的offsetlength.

这可能导致非常难以看到的内存问题.例如,您可能正在解析一些极小的文件(XML可能).如果您已将整个文件转换为String(而不是用于Reader"遍历"文件)并使用substring抓取您想要的位,您仍然char[]在幕后携带完整的文件大小的数组.我已经看过很多次了,很难发现.

实际上,这是为什么界面永远不能与实现完全分离的完美示例.几年前,这是一个完美的介绍(对我来说),为什么你应该怀疑第三方代码的质量.


请注意,此答案现已部分过时.在较新的JDK中,子字符串不会像这样.[相关相关答案](http://stackoverflow.com/questions/13803505/why-string-class-has-copy-constructor/13803521#13803521).
这个变化是在JDK 7u6中,标记为[bug no.4513622](http://bugs.sun.com/view_bug.do?bug_id=4513622).

5> 小智..:

SimpleDateFormat不是线程安全的.


它也很慢

6> David Plumpt..:

尝试阅读Java Puzzlers,它充满了可怕的东西,即使它不是你每天都碰到的东西.但它会破坏你对语言的大部分信心.


这是一本很棒的书,但谜题中的大多数"错误"都是*在实践中不会发生的事情.他们是非常深奥的边缘案例,让我说"无论如何,地球上的人都会写出来!"
大多数错误来自错误报告,所以很明显人们会碰到这些东西,然后变得非常困惑.(我写了书中的最后一个程序(名称除外),但故意.)
在"工作中的代码"中与Josh Blosh谈话.JB:为什么没有一本名为'C Puzzlers'的书呢?作者:因为这都是益智游戏.JB:没错,每种语言都有边缘案例.Java的功劳在于它们可以列在一本小书中

7> MBCook..:

有两个让我很烦恼.

日期/日历

首先,Java Date和Calendar类非常混乱.我知道有修复它们的建议,我只希望它们成功.

Calendar.get(Calendar.DAY_OF_MONTH)是从1开始的
Calendar.get(Calendar.MONTH)是从0开始的

自动拳击防止思考

另一个是Integer vs int(这适用于对象的任何原始版本).这特别是由于没有将Integer视为与int不同而导致的烦恼(因为你可以在很多时候因为自动装箱而对待它们).

int x = 5;
int y = 5;
Integer z = new Integer(5);
Integer t = new Integer(5);

System.out.println(5 == x);     // Prints true
System.out.println(x == y);     // Prints true
System.out.println(x == z);     // Prints true (auto-boxing can be so nice)
System.out.println(5 == z);     // Prints true
System.out.println(z == t);     // Prints SOMETHING

由于z和t是对象,即使它们保持相同的值,它们(很可能)也是不同的对象.你真正的意思是:

System.out.println(z.equals(t));   // Prints true

追踪这个可能是一种痛苦.你去调试一切,一切看起来都很好,你终于发现你的问题是5!= 5当两者都是对象时.

能够说

List stuff = new ArrayList();

stuff.add(5);

这么好看.它使Java变得更加可用,不必将所有那些"new Integer(5)"和"((Integer)list.get(3)).intValue()"放在所有地方.但这些好处伴随着这个问题.


z == t总是假的.两个单独新建的对象具有不同的对象标识.另一方面,如果你在两种情况下都说Integer.valueOf(5),那么它们就是同一个对象:-128到127之间的值应该是缓存值.
我花了两个8小时的时间来弄清楚为什么我们所有的日期都是一个月的假期......我正拉着我的头发!
-1.关于`z == t`示例你错了,正如@Chris Jester-Young所描述的那样.也许你把它与.NET中的类似例子混淆,其中`z == t`*可以*为真.

8> Tom Hawtin -..:
List list = new java.util.ArrayList();
list.add(1);
list.remove(1); // throws...

旧的API并没有考虑到拳击的设计,因此与原语和对象重载.



9> Claudiu..:

这个我刚刚遇到的:

double[] aList = new double[400];

List l = Arrays.asList(aList);
//do intense stuff with l

有谁看到了问题?


会发生什么,Arrays.asList()期望一个对象类型数组(例如,Double []).如果它只是为前一个ocde抛出一个错误,那就太好了.但是,asList()也可以采用这样的参数:

Arrays.asList(1, 9, 4, 4, 20);

那么代码所做的就是List用一个元素创建一个- a double[].

我应该想一下,当需要0ms才能对750000元素数组进行排序时......


来自Guava的`Doubles.asList`(http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/primitives/Doubles.html#asList%28double...%29)做了什么你想.类似地,`Ints.asList`对`int []`等做同样的事情.

10> anjanb..:

这个曾经打败过我几次,我听说有不少经验丰富的java开发人员浪费了很多时间.

ClassNotFoundException ---你知道类在类路径中但是你不确定为什么类没有被加载.

实际上,这个类有一个静态块.静态块中有一个异常,有人吃了异常.他们不应该.他们应该抛出ExceptionInInitializerError.所以,总是寻找静止的块来绊倒你.它还有助于移动静态块中的任何代码进入静态方法,以便使用调试器更容易调试方法.



11> John Nilsson..:

花车

我不知道很多次见过我

floata == floatb

应该进行"正确"的测试

Math.abs(floata - floatb) < 0.001

我真的希望BigDecimal的文字语法是默认的十进制类型...


这不是Java特有的,而是关于浮动指向数字的表示方式.至少C,C++,Python和Perl有这些问题,其他许多人都有这个问题.

12> Bill the Liz..:

不是特定于Java,因为许多(但不是全部)语言以这种方式实现它,但是%运算符不是真正的模运算符,因为它与负数一起使用.这使得它成为余数运算符,如果您不了解它,可能会带来一些惊喜.

以下代码似乎打印"偶数"或"奇数",但事实并非如此.

public static void main(String[] args)
{
    String a = null;
    int n = "number".hashCode();

    switch( n % 2 ) {
        case 0:
            a = "even";
            break;
        case 1:
            a = "odd";
            break;
    }

    System.out.println( a );
}

问题是"数字"的哈希码是负数,因此n % 2交换机中的操作也是负数.由于交换机中没有处理否定结果的情况,因此变量a永远不会被设置.该程序打印出来null.

%无论您使用何种语言,请确保您知道操作员如何处理负数.



13> Daniel Hille..:

从事件派发线程外部操作Swing组件可能会导致很难找到的错误.这甚至是我们(经验丰富的程序员,拥有3年6年的java经验)经常忘记!有时这些错误在编写正确的代码并随后不经意地重构之后潜入......

请参阅本教程为什么必须.



14> riadd..:

不可变字符串,这意味着某些方法不会更改原始对象,而是返回修改后的对象副本.从Java开始我曾经一直忘记这一点,并想知道为什么替换方法似乎不适用于我的字符串对象.

String text = "foobar";
text.replace("foo", "super");
System.out.print(text); // still prints "foobar" instead of "superbar"



15> mkoryak..:

我认为,当我还是一名年轻的程序员时,我总是会感到困惑,从你正在迭代的数组中删除时是并发修改异常:

  List list = new ArrayList();
    Iterator it = list.iterator();
    while(it.hasNext()){
      //some code that does some stuff
      list.remove(0); //BOOM!
  }



16> anjanb..:

如果你有一个与构造函数同名的方法,那么BUT有一个返回类型.虽然这个方法看起来像构造函数(对于菜鸟),但它不是.

将参数传递给main方法 - 新手习惯需要一些时间.

过世.作为在当前目录中执行程序的类路径的参数.

意识到字符串数组的名称并不明显

hashCode和equals:很多具有5年以上经验的java开发人员都不太了解它.

设置与列表

直到JDK 6,Java没有NavigableSets来让你轻松地遍历Set和Map.



17> John Nilsson..:

整数除法

1/2 == 0 not 0.5


虽然不是特定的java

18> Michael Borg..:

使用?泛型通配符.

人们看到它并认为他们必须,例如List在他们想要的时候使用List他们可以添加任何东西,而不必停下来认为List已经做到了.然后他们想知道为什么编译器不会让它们使用add(),因为它List实际上意味着"我不知道某种特定类型的列表",所以你唯一可以做的List就是从中获取Object实例.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有