你好 我想提请您注意一篇简短的文章。 本文适用于初学者。 但是,即使您是经验丰富的开发人员,也请不要下结论。
我希望该出版物不仅对初学者有用。
本出版物的目的:向初学者展示最常见的错误以及一些纠正错误的技巧。 显然,某些错误可能很复杂,并且由于某种原因或另一种原因而发生。 该出版物的目的是在某种程度上分析它们并帮助及早识别。 我希望该出版物对初学者有用。
错误清单:
1.错别字。 烦人的错别字不会立即显示
2.条件分配而不是比较
3.条件中的逻辑错误
4.错误的字符串比较
5.基本类型变量的初始化不正确
6.双重使用不当
7.构造函数中返回值的类型错误。
8.除以零。 POSITIVE_INFINITY
9.不考虑类的初始化顺序
10.局部变量隐藏了一个类变量
11.忽略算术表达式中的自动转换
12.带字节的无限循环,难以检测。
13.类的名称与存储它的文件的名称不同。
14.作为数组元素的对象未初始化。
15.使用public修饰符一次将多个类放在一个文件中
Java陷阱
所有编程语言都有其优点和缺点。 这是由于许多原因。 Java也不例外。 我试图收集新手Java程序员遇到的一些明显的和不明显的困难。 我相信有经验的程序员也会在我的文章中找到有用的东西。 练习,专心和积累的编程经验将帮助您避免许多错误。 但是最好事先考虑一些错误和困难。 我将给出一些带有代码和解释的示例。 通过对代码的注释,许多解释将对您清晰明了。 由于一些规则不是很明显,实践给了很多。 有些位于表面上,有些则隐藏在语言库或Java虚拟机中。 请记住,java不仅是具有一组库的编程语言,还是Java虚拟机。
对于这篇文章,我专门编写了带有详细注释的工作代码。 为了编写带有代码示例的文章,使用了Java 8,为了进行测试,将Java代码放在单独的程序包中。
示例:“ packageunderwaterRocks.simple;”
初学者面临什么困难?
错别字
碰巧的是,新手程序员所做的错别字一目了然。
代码示例:文件:“ Simple.java”
package underwaterRocks.simple; public class Simple { public static void main(String[] args) { int ival = 10; if(ival>0); { System.out.println(" "); } } }
说明 :“分号表示语句的结尾。 在这种情况下; 空语句的结尾。 这是一个逻辑错误。 这样的错误可能很难检测到。
编译器将认为一切正确。 条件(ival> 0); 在这种情况下没有意义。 因为这意味着:如果ival大于零,则不执行任何操作并继续。”
条件分配而不是比较
条件是变量分配。
这不是一个错误,但是应该证明使用这种技术是合理的。
boolean myBool = false; if(myBool = true) System.out.println(myBool);
在这段代码中,如果(myBool = true)表示:“将变量myBool设置为true,
如果表达式为真,则遵循括号后面的条件。”
在此代码中,条件将始终为true。 和System.out.println(myBool); 无论条件如何,都将始终执行。
==是相等性的比较。
=是一项作业,可以说a = 10; 例如:“但指定值为10”。
括号中的条件返回布尔值。
编写顺序无关紧要。 您可以像这样比较:(0 == a)或(5 == a)
如果忘记一个等号,例如(0 = a)或(5 = a),则编译器将通知您错误。 您分配一个值,而不是一个比较。
您也可以以可读的形式写一些时间间隔。
例如:您需要写:大于5小于10。
您可以这样写:(a> 4 && a <10),但是成功的话,您可以这样写:(4 <a && a <10),
现在您看到a在4到10之间,不包括这些值。 这更加明显。 显然,不包括这些值的a在4到10之间。
代码示例(间隔为3.9 []):
如果(3 <a && a <9)执行;
逻辑错误
if(condition){} if(condition){} else {}-else表示最接近的if。
这通常是初学者错误的原因。
无效的字符串比较
初学者经常使用==代替.equals来比较字符串。
变量初始化
考虑初始化基本类型的变量。
基元(字节,短整数,整数,长整数,字符,浮点数,双精度,布尔值)。
初始值。
byte 0 short 0 int 0 long 0L float 0.0f double 0.0d char '\u0000' String (or any object) null boolean false ( jvm)
注意事项:局部变量略有不同。
编译器永远不会将默认值分配给未初始化的局部变量。
如果您无法在声明它的地方初始化本地变量,
请记住在尝试使用之前为其分配一个值。
访问未初始化的局部变量将导致编译时错误。
在代码中确认此注释:文件:“ MyInitLocal.java”
package underwaterRocks.myInit; public class MyInitLocal { float classes_f; int classes_gi; public static void main(String[] args) { float f; int i; MyInitLocal myInit = new MyInitLocal(); System.out.println("myInit.classes_f = " + myInit.classes_f); System.out.println("myInit.classes_gi = " + myInit.classes_gi);
值范围:
byte ( , 1 , [-128, 127])
short ( , 2 , [-32768, 32767])
int ( , 4 , [-2147483648, 2147483647])
long ( , 8 , [-922372036854775808,922372036854775807])
float ( , 4 )
double ( , 8 )
char ( Unicode, 2 , 16 , [0, 65535])
boolean ( /, int, JVM)
char:char数据类型是单个16位Unicode字符。 它的最小值为“ \ u0000”(或0),最大值为“ \ uffff”(或65,535(含))。
Oracle文档
>>让我们尝试初始化一个数字类型为long的变量:922372036854775807。
没有任何事情对我们有利。 因为它是int类型的整数文字。
使用长文字正确初始化:922372036854775807L;
代码示例:文件:“ MyInitLocalLong.java”
package underwaterRocks.myInit; public class MyInitLocalLong { public static void main(String[] args) {
初始化变量时要查找什么。
此类型的变量的值范围。 用某种类型的文字初始化变量的事实。 用于显式和隐式强制转换。 关于类型兼容性。
使用Integer类型的shell时,应注意这些类型的自动打包和自动拆包。
双重使用不当
在这里您需要澄清。 这与滥用double类型无关。
我们正确使用。 只有结果才能使新手程序员感到惊讶。
文件:“ MinusDouble.java”
package underwaterRocks.tstDouble; public class MinusDouble { public static void main(String[] args) { double a = 4.64; double b = 2.64; System.out.println("ab = "+(ab)); } }
注意有关双精度型。 浮点数可让您以给定的相对误差和很大的范围进行计数。 在科学计算中,经常需要相对误差。
无效的双重比较
考虑双重类型。
代码示例:文件:“ MyDouble.java”
package underwaterRocks.myDouble; public class MyDouble { public static void main(String[] args) { double dx = 1.4 - 0.1 - 0.1 - 0.1 - 0.1; System.out.println("dx = " + dx);
双精度型在不需要高精度的地方很方便。 对于金融交易,此类型不合适。 尽管有些公司不是很诚实,但使用double型将其舍入到所需的一侧。 对于财务操作,BigDecimal类用于财务计算,因为由于精度损失和舍入结果错误的原因,实际原始类型不适用于该目的。 但是,使用BigInteger类可以获得更准确的结果。
类构造器
类构造函数与类名称匹配,不返回任何内容,甚至不返回void。
代码示例:文件:“ MyConstructor.java”
package underwaterRocks.myConstructor; public class MyConstructor { public MyConstructor(){ System.out.println(" void"); } public void MyConstructor(){ System.out.println(" c void"); } public static void main(String[] args) { MyConstructor myconst = new MyConstructor(); myconst.MyConstructor();
正如我们在代码中看到的,两个具有相同名称的方法:MyConstructor()和MyConstructor()。 其中一种方法不返回任何内容。 这是我们类的构造函数。 另一个带有void的方法是常规类方法。 如果您没有创建构造函数,或者您认为创建的类的构造函数为void,则编译器将创建默认构造函数,您会惊讶为什么构造函数不起作用。
被零除
您认为将是执行此类代码的结果。
文件:“ DivisionByZero.java”
package divisionByZero; import static java.lang.Double.POSITIVE_INFINITY; public class DivisionByZero { public static void main(String[] args) { try{ float f = 12.2f; double d = 8098098.8790d; System.out.println(f/0); System.out.println(d/0); System.out.println(POSITIVE_INFINITY == f/0); System.out.println(POSITIVE_INFINITY == d/0); } catch (NumberFormatException ex) { System.out.println("NumberFormatException"); } catch (ArithmeticException ex) { System.out.println("ArithmeticException"); } } }
执行代码将输出:
Infinity Infinity true true
将整数类型除以零将产生ArithmeticException。
java.lang.Double类定义常量
POSITIVE_INFINITY;
public static final float POSITIVE_INFINITY = 1.0d / 0.0d;
它将转换为等于Infinity的字符串。
初始化顺序
文件:“ InitClass.java”
package myInitClass; public class InitClass { InitClass(){
首先,执行所有静态块,然后执行初始化块,然后执行类构造函数。
它将显示:“ 123 Constructor”
局部变量隐藏了类变量尽管现代的IDE可以轻松检测到此错误,但我想更详细地考虑这种错误。 让我们从构造函数中的经典变量赋值开始。 这个例子是正确的。 没有错
public class MyClass { private int val = 0; public MyClass(int val) { this.val = val; } }
但是,如果在方法中而不是在类构造函数中使用此技术,会发生什么? 在通常的方法中,不建议使用此技术。 问题与班级的正确设计有关。
一个简单的解释:在方法中,与类变量同名的变量是该方法的局部变量。 您可以使用this.val访问类变量。 但是,如果类的设计不当,则这种方法的吸引力只会导致副作用,并且可能会降低代码的可读性。
算术类型转换是自动完成的这会导致烦人的错误。
使用字符串时,一种可能的解决方案:
byte bHundr = Byte.parseByte("100");
以下代码给出了另一个错误。
for (byte i = 1; i <= 128; i++) { System.out.println(i); }
在这种情况下,我们得到一个无限循环。
的解释。 键入字节[-128,127]。 128不再在此范围内。 发生溢出,并且循环重复。 在这种情况下使用字节的必要性令人怀疑。 尽管这种情况很少发生。 建议使用int而不是字节。 另一个建议是不要在算法中使用循环。
数组元素的对象未初始化 int[] cats = new int[10]; for(int i=0; i<cats.length;i++){ System.out.println("cats " + i + " = " + cats[i]); }
在这个例子中,我们有一个原始类型元素的数组。 如果不初始化它们,也不会发生任何不良情况。 它们将被分配默认值。 在这种情况下,值= 0。
让我们考虑另一个示例,该示例不在数组中包含基元,而是在数组中包含对象。
public class ArrInitObj { public static void main(String[] args) { MyObj[] cats = new MyObj[10]; for(int i=0; i<cats.length;i++){ System.out.println("cats " + i + " = " + cats[i]); System.out.println("cats " + i + ".val = " + cats[i].val);
解决此问题的方法是在使用它们之前初始化所有对象变量。 可以在MyObj类的构造函数中完成初始化。
类名与存储它的文件名不同现代IDE可以轻松检测到此类错误。 但是,尽管很少遇到这种错误。 考虑到大小写字母名称的差异,这将有助于注意。
使用public修饰符一次将多个类放在一个文件中该错误非常罕见。 IDE将立即向您发出警告。
文件名必须与公共类的名称匹配。
结论乍看之下,许多错误并不明显。 即使是经验丰富的程序员也可以这样做,但数量较少。 细心,实际经验,使用调试器和阅读文档将帮助您避免许多错误。
我希望您喜欢这篇文章并发现对您有所帮助。 我很高兴您的意见,评论,建议和愿望。 待续。 相反,添加如下。
参考文献Oracle Java代码设计指南>>>PS。 我的朋友们 没有您的帮助,我无法继续发布。 也就是说,没有经济机会。 如果该出版物确实对您有所帮助,并且您想继续,请支持我。 某个地方有一个按钮:“支持作者”。
希望您的理解。 谢谢啦 感谢Habr发布的机会。
如果缺乏支持,作者将被迫删除自己的出版物或将其隐藏在草稿中。 这不是最后通.。 如果有机会,它会派上用场,您可以提供帮助,然后单击作者支持按钮。