50 个 Java 开发常见错误及规避技巧 (Part 1)(1-20)

英文原文:50 Common Java Errors and How to Avoid Them (Part 1)

在开发 Java 软件时可能会遇到许多类型的错误,但大多数可以避免。 我们列举了 50 个最常见的 Java 软件错误,其中包含代码示例和教程,以帮助您解决常见的编码问题。

更多关于编写更好的 Java 程序的提示和技巧,请下载我们的“综合 Java 开发人员指南”,指南包含从工具到最好的网站及博客,YouTube 频道,有影响力的 Twitter,领英小组,播客,所有你需要用到的 Java 相关内容。

如果您正在使用 .NET,您还应该查看我们的 50 个最常见的 .NET 软件错误指南,以及如何避免这些错误。 如果您当前的挑战与 Java 相关,请继续阅读以了解最常见的问题及其解决方法。


编译器错误

编译器错误消息在Java软件代码在编译器执行时产生。需要重点记住的是,一个编译器可能为一个错误抛出多个错误消息。所以修复第一个错误并重编译,就能修复很多的问题。

1. “… 可预料的”

当编码出现遗漏时,就会发生这类错误。可能是缺失了一个括号或者分号。

private static double volume(String solidom, double alturam, double areaBasem, double raiom) double vol;

    if (solidom.equalsIgnoreCase("esfera"){
        vol=(4.0/3)*Math.pi*Math.pow(raiom,3);
    }
    else {
        if (solidom.equalsIgnoreCase("cilindro") {
            vol=Math.pi*Math.pow(raiom,2)*alturam;
        }
        else {
            vol=(1.0/3)*Math.pi*Math.pow(raiom,2)*alturam;
        }
    }
    return vol;
}

这种错误消息常常不会准确的定位到错误发生的位置。为了找到错误,建议:

  • 确保所有的左括号有对应匹配的右括号。

  • (使用 IDE,译者注)在代码行前的提示中检查。这种 Java 软件错误不要由编译器来关注,应该把更后面的工作交给它。

  • 有时候一个字符,比如一个左括号不应该写在 Java 代码的开始处。这样造成的结果是开发者不会写右括号去凑成一对。

对照这个“一个缺失的括号”的例子来制造一个错误。

2.“未封闭的 String 表达式”

“未封闭的 String 表达式”错误消息发生在 Sting 表达式结束时没有引号标记,错误消息将在发生错误的同一行提示出来。一个 String 表达式在源码中是一个值。

 public abstract class NFLPlayersReference {

    private static Runningback[] nflplayersreference;

    private static Quarterback[] players;

    private static WideReceiver[] nflplayers;

    public static void main(String args[]){

    Runningback r = new Runningback("Thomlinsion");

    Quarterback q = new Quarterback("Tom Brady");

    WideReceiver w = new WideReceiver("Steve Smith");

    NFLPlayersReference[] NFLPlayersReference;


        Run();// {         NFLPlayersReference = new NFLPlayersReference [3];

        nflplayersreference[0] = r;

        players[1] = q;

        nflplayers[2] = w;


            for ( int i = 0; i < nflplayersreference.length; i++ ) {

            System.out.println("My name is " + " nflplayersreference[i].getName());

            nflplayersreference[i].run();

            nflplayersreference[i].run();

            nflplayersreference[i].run();

            System.out.println("NFL offensive threats have great running abilities!");

        }

    }

    private static void Run() {

        System.out.println("Not yet implemented");

    }     

}

通常情况下,错误发生在:

  • String 表达式结束时没有使用引号标记。这种错误只要在 String 表达式结束是使用引号就能简单的改正

  • String 表达式超过一行时。长的 String 表达式可以被拆分成多个表达式,然后用 "+" 连接起来。

  • 引号是 String 表达式中的元素又没有使用下划线“\”进行转义。

阅读这篇《未封闭的 String 表达式的讨论》。

3. “非法的表达式开头” 

出现“非法表达式开头”错误的原因有很多。但它最终归类于一个不太有用的错误消息之一。有些开发者说这是由糟糕的代码造成的。

通常,创建表达式是用于生成新值或为变量赋值。编译器期望找到一个表达式,但找不到它,因为语法不符合预期。 (@StackOverflow)在下面这些语句中可以找到此错误。

// ADD IT HERE

       public void newShape(String shape) {

        switch (shape) {
            case "Line":
                Shape line = new Line(startX, startY, endX, endY);
            shapes.add(line);
            break;
                case "Oval":
            Shape oval = new Oval(startX, startY, endX, endY);
            shapes.add(oval);
            break;
            case "Rectangle":
            Shape rectangle = new Rectangle(startX, startY, endX, endY);
            shapes.add(rectangle);
            break;
            default:
            System.out.println("ERROR. Check logic.");
        }
        }
    } // REMOVE IT FROM HERE
    }

请浏览下这个讨论,关于如何解决“非法表达式开头”错误的方法 。 (@StackOverflow)

4. “找不到符号” 

这是一个非常常见的问题,因为 Java 中的所有标识符都需要在使用之前进行声明。 当编译代码时,编译器并不理解标识符的含义。

在你遇到“找不到符号”消息时可能有很多种原因:

  • 标识符声明时的拼写可能与代码中使用时的拼写不同。

  • 该变量从未被声明。

  • 该变量使用的位置与其声明的作用域不同。

  • 类并未被导入。

请通读关于“找不到符号”错误的讨论,其中也包含创建该问题的示例代码。(@StackOverflow)

5. “公共类 XXX 应该在文件中出现”

“公共类 XXX 应该在文件中出现”这个消息出现在类XXX和Java程序文件名不一致时。源代码只有在类名和 Java 文件名一样时才会被编译。(@coderanch):

package javaapplication3;  


  public class Robot {  
        int xlocation;  
        int ylocation;  
        String name;  
        static int ccount = 0;  

        public Robot(int xxlocation, int yylocation, String nname) {  
            xlocation = xxlocation;  
            ylocation = yylocation;  
            name = nname;  
            ccount++;         
        } 
  }

  public class JavaApplication1 { 



    public static void main(String[] args) {  

        robot firstRobot = new Robot(34,51,"yossi");  
        System.out.println("numebr of robots is now " + Robot.ccount);  
    }
  }

要修复这种情况:

  • 类名和文件名一样。

  • 确保这两个名字的大小写一致。

看 “公共类 XXX 应该在文件中出现”错误的例子。(@StackOverflow)

6. “不兼容类型” 

“不兼容的类型”是在赋值语句中尝试将变量与类型表达式匹配时触发的逻辑错误。通常是在代码尝试将文本字符写入到整数中时出现,反之亦然。 这不是 Java 语法错误。 (@StackOverflow

test.java:78: error: incompatible types
return stringBuilder.toString();
                             ^
required: int
found:    String
1 error

当编译器给出“不兼容的类型”消息时,确实没有一个简单的修复方案:

  • 有可以转换类型的函数。

  • 开发人员可能需要按照代码的预期修改之。

看一个例子,来说明如何通过使用字符串到整型的赋值来创建"不兼容类型"错误。(@StackOverflow)

7. “无效的方法声明;需求返回类型”

此错误表示方法签名中没有明确说明方法的返回类型。

public class Circle
{
    private double radius;
    public CircleR(double r)
    {
        radius = r;
    }
    public diameter()
    {
       double d = radius * 2;
       return d;
    }
}

有几种方式会触发“无效的方法声明; 需求返回类型“错误:

  • 忘记说明返回类型

  • 如果方法没有返回值,那么需要用“void”表示方法签名中的返回类型。

  • 构造函数名称不需要说明返回类型。 但是,如果构造函数名称中出现错误,那么编译器会将构造函数视为没有指定类型的方法。

下面是一个例子讲述构造函数命名怎么触发“无效的方法声明;需求返回类型”的错误 。 (@StackOverflow)

8. “类 Y 中的方法 X 不能应用于给定类型”

此错误消息是 Java 中最有用的错误消息之一。 它解释了方法签名是如何调用错误参数的。

RandomNumbers.java:9: error: method generateNumbers in class RandomNumbers cannot be applied to given types;
generateNumbers();

required: int[]

found:generateNumbers();

reason: actual and formal argument lists differ in length

方法在被调用时期望获取在方法声明中定义的某些参数。 检查方法声明、谨慎调用方法,以确保声明和调用的参数是兼容的。

这个讨论说明了 Java 错误消息如何识别在方法声明和方法调用中由参数导致的不兼容性。(@StackOverflow)

9. “缺少返回语句”

当一个方法缺少返回语句时,会发生“缺少返回语句”错误。 每一个有返回值的方法(非 void 类型)必须有一句字面上的语句用以返回返回值,以便在方法外调用该值。

public String[] OpenFile() throws IOException {

    Map<String, Double> map = new HashMap();

    FileReader fr = new FileReader("money.txt");
    BufferedReader br = new BufferedReader(fr);


    try{
        while (br.ready()){
            String str = br.readLine();
            String[] list = str.split(" ");
            System.out.println(list);               
        }
    }   catch (IOException e){
        System.err.println("Error - IOException!");
    }
}

下面列举了一些编译器抛出“缺少返回语句”的消息的原因:

  • 返回语句被错误地省略了

  • 一个方法没有返回任何值,但是在方法签名中没有声明为void类型

查看如何修复“缺少返回语句”的 Java 错误的示例(@StackOverflow)

10. “精度可能丢失”

当将超过一个变量可以保存的信息分配给该变量时,会发生“精度可能丢失”问题。如果发生这种情况,超出的信息将会被扔掉。如果这样做没问题,那么代码需要将变量显式地声明为新类型。

下面情况会发生“精度可能丢失”错误:

  • 将一个实数赋值给一个整型变量。

  • 将一个双精度浮点数赋值给一个整型变量。

Java 中原始数据类型解析展示了数据是怎么表示的。(@Oracle)

11. “解析时到达文件末尾”

这个错误信息经常发生在 Java 程序缺少“}”符号时。通常在代码末加上“}”符号能很快解决这个问题。

public class mod_MyMod extends BaseMod
public String Version()
{
     return "1.2_02";
}
public void AddRecipes(CraftingManager recipes)
{
   recipes.addRecipe(new ItemStack(Item.diamond), new Object[] {
      "#", Character.valueOf('#'), Block.dirt
   });
}

上述代码的运行结果是下列错误:

java:11: reached end of file while parsing }

代码编写工具和适当的代码缩进可以更容易地找到这些不对的大括号。

这个示例展示了缺少的大括号如何造成“解析时到达文件结尾”的错误消息。  (@StackOverflow)

12. “语句不可达”

“语句不可达”发生在当语句被放在一个不会被执行的位置时候。通常是在 break 语句或 return 语句后面。

for(;;){
   break;
   ... // unreachable statement
}


int i=1;
if(i==1)
  ...
else
  ... // dead code

通常简单地移动 return 语句就能解决这个错误。阅读这个讨论:如何解决语句不可达的 Java 软件错误。(@StackOverflow)

13. “变量 x 可能未被初始化”

这个问题发生在当方法内局部变量在声明时没有被初始化的时候。当一个变量未被初始化但是出现在 if 语句中的时候会发生该错误。

int x;
if (condition) {
    x = 5;
}
System.out.println(x); // x may not have been initialized

阅读这个讨论怎样避免发生“变量 x 可能未被初始化”的错误 (@reddit)

14. “操作符 ... 不能应用于 x”

这个情况发生于当操作符应用于没有定义其使用方法的类型上。

operator < cannot be applied to java.lang.Object,java.lang.Object

当 Java 代码尝试使用 string 类型进行数学计算时会经常出现这个问题。为了解决它,string 需要被转化为 integer 或 float。

阅读这个示例:非数值类型如何导致操作符不能应用于某类型的 Java 软件错误警告。(@StackOverflow)

15. “不能转换的类型”

“不能转换的类型”错误发生在 Java 代码尝试进行非法转换的时候。

TypeInvocationConversionTest.java:12: inconvertible types
found   : java.util.ArrayList<java.lang.Class<? extends TypeInvocationConversionTest.Interface1>>
required: java.util.ArrayList<java.lang.Class<?>>
    lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
                                                     ^

例如,boolean 不能转换为 int。

阅读这个关于在 Java 软件中寻找转换不能转换类型的方法的讨论。(@StackOverflow)

16. “缺少返回值”

当返回语句返回一个错误的类型时,你就会收到“缺少返回值”消息。例如下列代码:

public class SavingsAcc2 {
    private double balance;
    private double interest;

    public SavingsAcc2() {
        balance = 0.0;
        interest = 6.17;
    }
    public SavingsAcc2(double initBalance, double interested) {
        balance = initBalance;
        interest = interested;
    }
    public SavingsAcc2 deposit(double amount) {
        balance = balance + amount;
        return;
    }
    public SavingsAcc2 withdraw(double amount) {
        balance = balance - amount;
        return;
    }
    public SavingsAcc2 addInterest(double interest) {
        balance = balance * (interest / 100) + balance;
        return;
    }
    public double getBalance() {
        return balance;
    }
}

返回下列错误信息:

SavingsAcc2.java:29: missing return value 
return; 
^ 
SavingsAcc2.java:35: missing return value 
return; 
^ 
SavingsAcc2.java:41: missing return value 
return; 
^ 
3 errors

通常,那些返回语句没有返回任何东西。

阅读这个关于怎样避免“缺少返回值”的 Java 软件错误消息的讨论。(@coderanch)

17. “返回类型为 void 的方法不能返回一个值”

当一个返回类型为 void 的方法尝试返回任何值的时候就会发生这个 Java 错误,例如下面的例子:

public static void move()
{
    System.out.println("What do you want to do?");
    Scanner scan = new Scanner(System.in);
    int userMove = scan.nextInt();
    return userMove;
}

public static void usersMove(String playerName, int gesture)
{
    int userMove = move();

    if (userMove == -1)
    {
        break;
    }

通常改变方法签名,使之和返回语句的返回类型相配就能解决这个问题。在上述例子中,void 可以改为 int:

public static int move()
{
    System.out.println("What do you want to do?");
    Scanner scan = new Scanner(System.in);
    int userMove = scan.nextInt();
    return userMove;
}

阅读这个关于怎样解决“返回类型为 void 的方法不能返回一个值”的问题的讨论。(@StackOverflow)

18. “非静态变量 ... 不能在静态上下文中被引用”

当编译器尝试在一个静态方法中访问一个非静态变量时会发生该错误。 (@javinpaul):

public class StaticTest {

    private int count=0;
    public static void main(String args[]) throws IOException {
        count++; //compiler error: non-static variable count cannot be referenced from a static context
    }
}

为了解决“非静态变量 ... 不能在静态上下文中被引用”的错误,有下述两种方法:

  • 在签名中将变量声明为静态变量。

  • 在静态方法中创建一个非静态对象的示例

阅读这个指南,解释了静态和非静态变量的不同点。(@sitesbay)

19. “非静态方法 ... 不能在静态上下文中被引用”

这个情况发生在 Java 代码尝试在非静态类中调用非静态方法的时候。例如下述代码:

class Sample
{
   private int age;
   public void setAge(int a)
   {
      age=a;
   }
   public int getAge()
   {
      return age;
   }
   public static void main(String args[])
   {
       System.out.println("Age is:"+ getAge());
   }
}

将会返回下述错误:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Cannot make a static reference to the non-static method getAge() from the type Sample

为了在静态方法中调用非静态方法,可以声明一个类的实例来调用这个非静态方法。

阅读这个关于非静态方法和静态方法的不同点的解释。

20. “(array) <X> Not Initialized” (数组未初始化)

当数组已声明但未初始化时,你将得到“(array)<X>未初始化”的消息。 数组的长度是固定的,因此每个数组都需要按照实际长度进行初始化。

以下代码是可以接受的:

AClass[] array = {object1, object2}

下面也是可以的:

AClass[] array = new AClass[2];
...
array[0] = object1;
array[1] = object2;

但是这个不行:

AClass[] array;
...
array = {object1, object2};

请阅读关于在 Java 软件中如何初始化数组的讨论。(@StackOverflow)

接下来的内容

现在我们已经讨论了编译器错误,下次我们将深入讨论各种可能出现的运行时异常,这些异常会浪费你一整天时间。 就像本部分,它们将包含代码块、解释和相关链接,以帮助您尽快修复代码。

原文地址:

https://www.oschina.net/translate/50-common-java-errors-and-how-to-avoid-them-part-1?lang=chs&page=1#


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值