“嗨,阿米戈!让我们继续谈谈错误。这一次,我们将探讨编译器不会总是帮助你的错误。注意,你会学到一些关于你自己的东西。”

“我准备好倾听了,迭戈。我希望这不会让我太尴尬。”

比较对象==

“我们最喜欢的新手程序员错误列表从使用==运算符比较对象(尤其是字符串)开始”

例子:

Scanner console = new Scanner(System.in);
String s1 = console.nextLine();
String s2 = console.nextLine();
if (s1 == s2)
{
   System.out.println("The strings are equal");
}

“我经常这样做。现在我可以清楚地看到这段代码永远不会显示“字符串相等”,因为该if语句比较对两个不同字符串对象的引用。”

“是的。这就是为什么正确的选项是:

Scanner console = new Scanner(System.in);
String s1 = console.nextLine();
String s2 = console.nextLine();
if (s1.equals(s2))
{
   System.out.println("The strings are equal");
}

改变一个String对象

“新手程序员经常忘记类的所有对象都是不可变的,并且类的每个方法String都会返回一个新对象——当前对象永远不会改变。”

“就在不久之前,我才知道什么是不可变的,但我想我已经做到了。

“我相当确定。示例:

String s = "Hello";
s.toUpperCase (); // Convert to uppercase

“此代码与正确的代码非常相似,但它不会按预期工作。该toUpperCase()方法不会更改调用它的对象。正确的代码如下所示:

String s = "Hello";
String result = s.toUpperCase(); // Convert to uppercase

“没错,我也这么做了,但我什至没有真正理解哪里出了问题。谢谢你的澄清!”

忘记初始化作为数组元素的对象

“另一个常见的错误是忘记初始化数组变量。示例:

int[] array;
array[0] = 1;
array[0] = 2;

“此代码不起作用:您需要显式地将数组变量设置为对将存储数组元素的容器对象的引用。正确版本:

int[] array = new int[10];
array[0] = 1;
array[0] = 2;

使用局部变量而不是实例变量。

“新手不喜欢为变量起一个又长又有意义的名字。”

“这是真的。为了快速完成事情,我有时会为变量命名,例如abi。”

“不要那样做。当代码有几个这样的变量时,这是一件残忍的事情:

将数字 99 放入数组的 100 个单元格中
class Solution
{
  public static int a = 99;
  public static int i = 100;

  public static void main(String[] args)
  {
    int[] a = new int[i];
    for (int i = 0; i < 10; i++)
    {
      a[i] = a;
    }
  }
}

“在具有专有名称的代码中出错要困难得多。正确的版本如下所示:

将数字 99 放入数组的 100 个单元格中
class Solution
{
   public static int value = 99;
   public static int count = 100;

   public static void main(String[] args)
   {
      int[] a = new int[count];
      for (int i = 0; i < 10; i++)
      {
         a[i] = value;
      }
   }
}

删除集合项

“你已经研究过收藏品了吗?”

“真的只有一只眼睛。”

“如果你不知道我在说什么,那就给自己做个笔记,以后看看。很多时候会出现需要从集合中移除某个元素的情况。代码大概是这样的这:

ArrayList<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, 0, -5, -7, -12, 5, 15);

for (Integer value: list)
   if (value < 0)
      list.remove(value);

“此代码将不起作用,因为您不能使用for-each循环同时遍历集合的元素并修改该集合。

“有几种解决方案。首先,您可以遍历一个集合并更改另一个集合:

解决方案 1
ArrayList<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, 0, -5, -7, -12, 5, 15);

ArrayList<Integer> copy = new ArrayList<Integer>(list);
for (Integer value: copy)
   if (value < 0)
      list.remove(value);

“其次,从 Java 8 开始,集合有一个removeIf()方法,您可以向该方法传递一个规则(lambda 函数)来指示要删除的元素。示例:

方案二
ArrayList<Integer> list = new ArrayList<Integer>();
Collections.addAll(list, 0, -5, -7, -12, 5, 15);

list.removeIf( x-> x<0 );

将多个带有修饰符的类public放入一个文件中

“一个文件中只能有一个公共类。一个文件中可以声明更多的类,但它们必须是公共类的内部类,或者没有修饰符。示例public

Solution.java 文件的内容 笔记
public class Solution
{
}
public class Main
{
}
这是不允许的:一个文件中有两个公共类。
public class Solution
{
}
class Main
{
}
但你可以做到这一点。主类不公开
public class Solution
{
  public static class Main
  {
  }
}
你可以做到这一点。主类是一个嵌套类

main()从静态方法调用类的普通(非静态)方法

“有时,新手程序员会尝试从方法或其他静态方法访问非静态变量和方法main()。当然,这样的代码是行不通的。

public class Solution
{
   public int n = 100;
   public int[] createArray()
   {
      return new int[n];
   }

   public static void main(String[]args)
   {
      int[] array = createArray();
   }
}

“该main方法只能引用静态方法/变量。好吧,或者它必须首先创建该类的实例Solution,然后才能调用该对象的非静态方法。示例:

解决方案 1 方案二
public class Solution
{
  public static int n = 100;

  public static int[] createArray()
  {
    return new int[n];
  }

  public static void main(String[]args)
  {
    int[] array = createArray();
  }
}
public class Solution
{
  public int n = 100;

  public int[] createArray()
  {
    return new int[n];
  }

  public static void main(String[]args)
  {
    Solution sol = new Solution();
    int[] array = sol.createArray();
  }
}

像方法一样声明构造函数

“另一个常见的错误是错误地声明了类构造函数。构造函数的名称必须与类的名称相同,并且构造函数没有结果类型。最常见的错误如下所示:

public class Person
{
   private String value;

   void Person(String value)
   {
      this.value = value;
   }
}
这里不应该有返回类型
public class Person
{
   private String value;

   constructor(String value)
   {
      this.value = value;
   }
}
构造函数名称无效。它必须与类名匹配
public class Person
{
   private String value;

   Person(String value)
   {
      value = value;
   }
}
this 不见了。该value变量将被分配给自己
public class Person
{
   private String value;

   Person(String value)
   {
      this.value = value;
   }
}
这都是正确的。

接口继承不正确

“Java 的创造者试图让它非常接近英语,所以他们为某些相关概念选择了不同的关键词。

当一个类继承一个类时,你必须使用关键字extends

class Pet
{
}

class Cat extends Pet
{
}

“当一个类继承一个接口,或者更准确地说,实现它时,你需要使用关键字implements

interface Meow
{
}

class Cat implements Meow
{
}

"当一个接口继承一个接口时,使用extends关键字:

interface Meow
{
}

interface Voice extends Meov
{
}

breakswitch声明中省略

break“今天的最后一个错误,但不是初学者的最后一个错误,是没有在声明中包含声明switch。示例:

错误的 正确的
LocalDate date = LocalDate.now();
DayOfWeek day = date.getDayOfWeek();
switch (day)
{
   case MONDAY:
      System.out.println("Monday");
   case TUESDAY:
      System.out.println("Tuesday");
   case WEDNESDAY:
      System.out.println("Wednesday");
   case THURSDAY:
      System.out.println("Thursday");
   case FRIDAY:
      System.out.println("Friday");
   case SATURDAY:
      System.out.println("Saturday");
   case SUNDAY:
      System.out.println("Sunday");
}
LocalDate date = LocalDate.now();
DayOfWeek day = date.getDayOfWeek();
switch (day)
{
   case MONDAY:
      System.out.println("Monday");
      break;
   case TUESDAY:
      System.out.println("Tuesday");
      break;
   case WEDNESDAY:
      System.out.println("Wednesday");
      break;
   case THURSDAY:
      System.out.println("Thursday");
      break;
   case FRIDAY:
      System.out.println("Friday");
      break;
   case SATURDAY:
      System.out.println("Saturday");
      break;
   case SUNDAY:
      System.out.println("Sunday");
      break;
}

“你知道的,迭戈……从你在这里提出的一系列错误来看,感觉你一直在阅读我的个人日记……或者你一直在看着我解决任务。”

“哈!不要怀疑,我看过,追踪过,还会继续做,所以要提高警惕!”

“???”

“你别着急,开玩笑的,提高警惕,少犯蠢事。”