“嗨,阿米戈!讓我們繼續談談錯誤。這一次,我們將探索編譯器不會總是幫助你的錯誤。注意,你會學到一些關於你自己的東西。”

“我準備好傾聽了,迭戈。我希望這不會讓我太尷尬。”

比較對象==

“我們最喜歡的新手程序員錯誤列表從使用==運算符比較對象(尤其是字符串)開始”

例子:

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;
}

“你知道的,迭戈……從你在這裡提出的一系列錯誤來看,感覺你一直在閱讀我的個人日記……或者你一直在看著我解決任務。”

“哈!不用懷疑,我看過,跟踪過,還會繼續做,所以要提高警惕!”

“???”

“你別著急,開玩笑的,提高警惕,少犯蠢事。”