JavaRush /จาวาบล็อก /Random-TH /ข้อผิดพลาดของโปรแกรมเมอร์ Java มือใหม่ ส่วนที่ 1
articles
ระดับ

ข้อผิดพลาดของโปรแกรมเมอร์ Java มือใหม่ ส่วนที่ 1

เผยแพร่ในกลุ่ม

1. ชื่อของคลาสแตกต่างจากชื่อของไฟล์ที่เก็บไว้

กรอบงาน Java ทั้งหมดที่ฉันใช้ รวมถึง Javasoft JDK ถือว่าซอร์สโค้ดสำหรับคลาสที่มีตัวแก้ไขสาธารณะนั้นถูกจัดเก็บไว้ในไฟล์ที่มีชื่อเดียวกันกับชื่อคลาสและนามสกุล .java ทุกประการ การไม่ปฏิบัติตามแบบแผนนี้อาจทำให้เกิดปัญหามากมายที่จะปรากฏขึ้นระหว่างการคอมไพล์
ข้อผิดพลาดของโปรแกรมเมอร์ Java มือใหม่  ตอนที่ 1 - 1
นักเรียนมือใหม่ (โปรแกรมเมอร์) มักจะลืมหลักเกณฑ์นี้ไป เช่น ตั้งชื่อไฟล์ให้สอดคล้องกับงาน Lab6.java ตัวอย่างที่ไม่ถูกต้อง: ชื่อไฟล์Lab6.java
public class Airplane extends Vehicle
  Seat pilot;
  public Airplane() {
    pilot = new Seat();
  }
}
ตัวอย่างที่ถูกต้อง: ชื่อไฟล์Airplane.java
public class Airplane extends Vehicle
  Seat pilot;
  public Airplane() {
    pilot = new Seat();
  }
}
โปรดทราบ:ชื่อคลาสจะถือว่าขึ้นต้นด้วยตัวพิมพ์ใหญ่ ระบบปฏิบัติการที่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ในชื่อไฟล์อาจทำให้เกิดปัญหาเพิ่มเติม โดยเฉพาะอย่างยิ่งสำหรับนักเรียนที่เรียน Java บน Unix ซึ่งคุ้นเคยกับระบบการตั้งชื่อไฟล์ DOS คลาสMotorVehicleควรถูกเก็บไว้ในไฟล์MotorVehicle.javaแต่ไม่ใช่ในmotorvehicle.java.

2. การเปรียบเทียบโดยใช้==

java.lang.Stringใน Java สตริงเป็นวัตถุของคลาส ตัวดำเนินการนำ==ไปใช้กับวัตถุจะตรวจสอบความเท่าเทียมกันของการอ้างอิงถึงวัตถุ! บางครั้งนักเรียนไม่เข้าใจความหมายของโอเปอเรเตอร์==และพยายามใช้มันเพื่อเปรียบเทียบสตริง ตัวอย่างที่ไม่ถูกต้อง:
// проверим, equals ли первый аргумент "-a"
if (args[0] == "-a") {
    optionsAll = true;
}
วิธีที่ถูกต้องในการเปรียบเทียบ 2 สายเพื่อความเท่าเทียมกันคือการใช้เมธอดequals()คลาส java.lang.Stringจะส่งกลับtrueหากสตริงมีความยาวเท่ากันและมีอักขระเหมือนกัน (หมายเหตุ: จริงๆ แล้วสิ่งนี้ไม่ได้รับประกันความเท่าเทียมกัน จริงๆ แล้วequalsจะตรวจสอบว่า 2 สตริงมีอักขระเท่ากันทีละอักขระหรือไม่) ตัวอย่างที่ถูกต้อง:
//  проверим, equals ли первый аргумент "-a"
if ("-a".equals(args[0])) {
    optionsAll = true;
}
ข้อผิดพลาดนี้โง่เพราะจริงๆ แล้วโค้ด Java กลายเป็นว่าถูกต้องตามหลักไวยากรณ์ แต่สุดท้ายมันก็ไม่ทำงานตามที่คาดไว้ นักเรียนบางคนยังพยายามใช้ตัวดำเนินการเปรียบเทียบแทน>วิธี<=การcompareTo()เรียน java.lang.Stringข้อผิดพลาดนี้ตรวจพบได้ง่ายกว่าเนื่องจากทำให้เกิดข้อผิดพลาดระหว่างขั้นตอนการคอมไพล์

3. ลืมเริ่มต้นวัตถุที่เป็นองค์ประกอบของอาร์เรย์

ใน Java อาร์เรย์ของวัตถุจริงๆ แล้วเป็นอาร์เรย์ของการอ้างอิงวัตถุ การสร้างอาร์เรย์เป็นเพียงการสร้างชุดการอ้างอิงที่ไม่ได้ชี้ไปที่สิ่งใดๆ (นั่นคือ สิ่งเหล่านี้เป็นโมฆะ) หากต้องการสร้างอาร์เรย์ของออบเจ็กต์ "เต็ม" จริงๆ คุณต้องเริ่มต้นแต่ละองค์ประกอบของอาร์เรย์ นักเรียนหลายคนไม่เข้าใจสิ่งนี้ พวกเขาเชื่อว่าด้วยการสร้างอาร์เรย์ของวัตถุ พวกเขาจะสร้างวัตถุขึ้นมาเองโดยอัตโนมัติ (ในกรณีส่วนใหญ่ นักเรียนนำแนวคิดนี้มาจากภาษา C++ โดยที่การสร้างอาร์เรย์ของอ็อบเจ็กต์ส่งผลให้เกิดการสร้างอ็อบเจ็กต์ด้วยตนเองโดยการเรียกคอนสตรัคเตอร์เริ่มต้น) ในตัวอย่างด้านล่าง นักเรียนต้องการสร้างวัตถุ 3 ชิ้นในชั้นStringBufferเรียน รหัสจะคอมไพล์โดยไม่มีข้อผิดพลาด แต่จะมีข้อยกเว้นเกิดขึ้นในบรรทัดสุดท้ายNullPointerExceptionซึ่งมีการเข้าถึงวัตถุที่ไม่มีอยู่จริง ตัวอย่างที่ไม่ถูกต้อง:
// Создаем массив из StringBuffer
StringBuffer [] myTempBuffers;
myTempBuffers = new StringBuffer[3];
myTempBuffers[0].add(data);
เพื่อหลีกเลี่ยงข้อผิดพลาดนี้ คุณต้องจำไว้ว่าต้องเริ่มต้นองค์ประกอบอาร์เรย์ ตัวอย่างที่แก้ไข:
// Создаем массив из StringBuffer и инициализируем элементы
StringBuffer [] myTempBuffers;
myTempBuffers = new StringBuffer[3];
for (int ix = 0; ix < myTempBuffers.length; ix++)
     myTempBuffers[ix] = new StringBuffer();

myTempBuffers[0].add(data);

4. การวางหลายคลาสพร้อมตัวแก้ไขในไฟล์เดียวในคราวเดียวpublic

ไฟล์ต้นฉบับ Java มีความเชื่อมโยงในลักษณะบางอย่างกับคลาสที่มีอยู่ในไฟล์เหล่านั้น ความสัมพันธ์สามารถมีลักษณะดังนี้: คลาส Java ใด ๆ จะถูกเก็บไว้ในไฟล์ไม่เกินหนึ่งไฟล์ ในไฟล์ซอร์สโค้ดใดๆ คุณสามารถวางได้ไม่เกิน 1 คลาสด้วยตัวpublicแก้ไข หากมีคลาสที่มีตัวแก้ไขในไฟล์ซอร์สโค้ดpublicชื่อไฟล์และชื่อคลาสจะต้องเหมือนกันอย่างเคร่งครัด (หมายเหตุการแปล: แล้วแต่กรณี ดูจุดที่ 1) บางครั้งนักเรียนลืมกฎข้อที่ 2 ซึ่งนำไปสู่ข้อผิดพลาด ในการรวบรวมเวที ข้อความแสดงข้อผิดพลาดสำหรับกฎข้อที่ 2 และ 3 จะเหมือนกัน (ซึ่งทำให้ยากต่อการจดจำข้อผิดพลาดนี้)

5. การทดแทนฟิลด์คลาสด้วยตัวแปรท้องถิ่น

Java ช่วยให้คุณสามารถประกาศตัวแปรภายในวิธีการที่มีชื่อตรงกับเขตข้อมูลของชั้นเรียน ในกรณีนี้ ตัวแปรในเครื่องจะมีความสำคัญกว่าและจะใช้แทนช่อง คอมไพเลอร์จะส่งข้อผิดพลาดหากตัวแปรที่มีชื่อเดียวกันเป็นประเภทที่แตกต่างกัน หากเป็นประเภทเดียวกันก็จะไม่มีข้อผิดพลาดในการคอมไพล์ และสาเหตุของการทำงานของโปรแกรมที่ไม่ถูกต้องจะไม่ชัดเจน ตัวอย่างที่ไม่ถูกต้อง:
public class Point3 {
    int i = 0;
    int j = 0;
    int k = 0;

    public boolean hits(Point[] p2list) {
      for(int i = 0; i < p2list.length; i++) {
        Point p2 = p2list[i];
        if (p2.x == i && p2.y == j)
          return true;
      }
      return false;
    }
}
มีหลายวิธีในการแก้ไขข้อผิดพลาดนี้ วิธีที่ง่ายที่สุดคือการเข้าถึงฟิลด์คลาสโดยใช้ implicit this: this.Name_поляpointer วิธีที่ดีที่สุดคือการเปลี่ยนชื่อฟิลด์คลาสหรือตัวแปรโลคัล จากนั้นการทดแทนจะไม่เกิดขึ้น (แปลโดยประมาณ: วิธีที่ 2 ไม่ใช่วิธีของเรา ยิ่งไปกว่านั้นไม่รับประกันว่าสักวันหนึ่งฉันจะไม่เปลี่ยนเขตข้อมูลของตัวแปรโดยไม่ตั้งใจ ความยากที่ยิ่งกว่านั้นเกิดขึ้นกับการสืบทอดเมื่อฉันไม่เห็นเลยว่าช่องใด ชั้นเรียนมี ) ตัวอย่างที่แก้ไขแล้ว:
// One way to fix the problem
  int i = 0;
  int j = 0;
  int k = 0;

  public boolean hits(Point[] p2list) {
    for(int i = 0; i < p2list.length; i++) {
      Point p2 = p2list[i];
      if (p2.x == this.i && p2.y == this.j)
        return true;
    }
    return false;
  }

  // *****************************
  // Лучший способ
  int x = 0;
  int y = 0;
  int z = 0;

  public boolean hits(Point[] p2list) {
    for(int i = 0; i < p2list.length; i++) {
      Point p2 = p2list[i];
      if (p2.x == x && p2.y == y)
        return true;
    }
    return false;
  }
อีกจุดที่เป็นไปได้สำหรับข้อผิดพลาดนี้คือการตั้งชื่อของพารามิเตอร์เมธอดให้เหมือนกับชื่อของฟิลด์คลาส สิ่งนี้ดูดีในตัวสร้าง แต่ไม่เหมาะสำหรับวิธีการปกติ

ประมาณ การแปล

วุ่นวายเล็กน้อย แต่นั่นคือส่วนสำคัญ

public class Test {
   private int param = 0;

   public Test(int param) {
      this.param = param;
   }
}

นั่นคือทุกอย่างดูสวยงามในตัวสร้าง แต่ไม่ควรใช้กับวิธีการทั่วไป

6. ลืมเรียกคอนสตรัคเตอร์พาเรนต์ (ซูเปอร์คลาส)

เมื่อคลาสขยายคลาสอื่น ตัวสร้างคลาสย่อยแต่ละตัวจะต้องเรียกตัวสร้างคลาสพิเศษบางตัว โดยปกติจะทำได้โดยการเรียกตัวสร้างคลาสพิเศษด้วยเมธอดsuper(x)ที่วางอยู่บนบรรทัดแรกของตัวสร้าง ถ้าไม่มีการเรียกในบรรทัดแรกของ Constructor super(x)คอมไพลเลอร์จะแทรกการเรียกนี้เอง แต่ไม่มีพารามิเตอร์super(): (ประมาณทรานส์: x...se แต่ฉันไม่รู้) บางครั้งนักเรียนก็ลืมข้อกำหนดนี้ไป โดยปกติแล้วนี่ไม่ใช่ปัญหา: การเรียกไปยังตัวสร้างซูเปอร์คลาสจะถูกแทรกโดยคอมไพเลอร์และทุกอย่างทำงานได้ดี อย่างไรก็ตาม ถ้าซูเปอร์คลาสไม่มีตัวสร้างเริ่มต้น คอมไพเลอร์จะส่งข้อผิดพลาด ในตัวอย่างด้านล่าง ตัวสร้างคลาสซูเปอร์คลาสทั้งหมดjava.io.Fileมีพารามิเตอร์ 1 หรือ 2 ตัว: ตัวอย่างที่ผิดพลาด:
public class JavaClassFile extends File {
    String classname;
    public JavaClassFile(String cl) {
        classname = cl;
    }
}
วิธีแก้ไขปัญหาคือการแทรกการเรียกที่ชัดเจนไปยังตัวสร้างซูเปอร์คลาสที่ถูกต้อง: ตัวอย่างที่ถูกต้อง:
public class JavaClassFile extends File {
    String classname;
    public JavaClassFile(String cl) {
        super(cl + ".class");
        classname = cl;
    }
}
สถานการณ์ที่ไม่พึงประสงค์มากขึ้นเกิดขึ้นเมื่อซูเปอร์คลาสมีตัวสร้างเริ่มต้น แต่ไม่ได้เตรียมใช้งานอ็อบเจ็กต์ได้อย่างสมบูรณ์ ในกรณีนี้โค้ดจะคอมไพล์ แต่เอาต์พุตของโปรแกรมอาจไม่ถูกต้องหรืออาจมีข้อยกเว้นเกิดขึ้น

7. การจับข้อยกเว้นอย่างไม่ถูกต้อง

ระบบการจัดการข้อยกเว้นของ Java ค่อนข้างทรงพลัง แต่ยากสำหรับผู้เริ่มต้นที่จะเข้าใจ นักเรียนที่เชี่ยวชาญ C++ หรือ Ada มักจะไม่มีปัญหาเช่นเดียวกับโปรแกรมเมอร์ C และ Fortran ตัวอย่างด้านล่างแสดงข้อผิดพลาดทั่วไปบางประการ ในตัวอย่างนี้ ไม่มีชื่อข้อยกเว้น คอมไพเลอร์จะระบุข้อผิดพลาดนี้ในขั้นตอนการคอมไพล์ ดังนั้นจึงง่ายต่อการแก้ไขด้วยตนเอง ตัวอย่างที่ไม่ถูกต้อง:
try {
    stream1 = new FileInputStream("data.txt");
} catch (IOException) {
    message("Could not open data.txt");
}
ตัวอย่างที่แก้ไข:
try {
   stream1 = new FileInputStream("data.txt");
} catch (IOException ie) {
   message("Could not open data.txt: " + ie);
}
ลำดับของบล็อกcatchจะกำหนดลำดับในการตรวจพบข้อยกเว้น จะต้องคำนึงว่าแต่ละบล็อกดังกล่าวจะจับข้อยกเว้นทั้งหมดของคลาสที่ระบุหรือคลาสย่อยใด ๆ หากคุณไม่คำนึงถึงสิ่งนี้ คุณอาจจบลงด้วย catch block ที่ไม่สามารถเข้าถึงได้ ซึ่งคอมไพลเลอร์จะชี้ให้เห็น ในตัวอย่างด้านล่างSocketExceptionเป็นคลาสย่อยของIOException. ตัวอย่างที่ไม่ถูกต้อง:
try {
    serviceSocket.setSoTimeout(1000);
    newsock = serviceSocket.accept();
} catch (IOException ie) {
    message("Error accepting connection.");
} catch (SocketException se) {
    message("Error setting time-out.");
}
ตัวอย่างที่แก้ไข:
try {
    serviceSocket.setSoTimeout(1000);
    newsock = serviceSocket.accept();
} catch (SocketException se) {
    message("Error setting time-out.");
} catch (IOException ie) {
    message("Error accepting connection.");
}
หากเป็นไปได้ที่จะมีข้อยกเว้นเกิดขึ้นในโค้ดของคุณซึ่งไม่ถูกบล็อกใดๆ จับได้try-catchข้อยกเว้นนี้ควรได้รับการประกาศในส่วนหัวของเมธอด RuntimeException( ซึ่งไม่จำเป็นสำหรับข้อยกเว้น - คลาสย่อยของคลาส ) บางครั้งนักเรียนลืมไปว่าการเรียก method อาจทำให้เกิดข้อยกเว้นได้ try-catchวิธีที่ง่ายที่สุดในการแก้ไขปัญหานี้ คือ ใส่การเรียกเมธอดไว้ในบล็อก ตัวอย่างที่ไม่ถูกต้อง:
public void waitFor(int sec) {
    Thread.sleep(sec * 1000);
}
ตัวอย่างที่แก้ไข:
public void waitFor(int sec) throws InterruptedException {
    Thread.sleep(sec * 1000);
}

8. วิธีการเข้าถึงมีแบบvoid

นี่เป็นข้อผิดพลาดที่ง่ายมาก นักเรียนสร้างวิธีการในการเข้าถึงตัวแปร แต่ระบุว่าวิธีการนั้นจะไม่ส่งคืนสิ่งใดๆ (วางตัวแก้ไขvoidในส่วนหัวของวิธีการ) เพื่อแก้ไขข้อผิดพลาดนี้ คุณต้องระบุประเภทการคืนสินค้าที่ถูกต้อง ตัวอย่างที่ไม่ถูกต้อง:
public class Line {
    private Point start, end;
    public void getStart() {
      return start;
    }
}
ตัวอย่างที่แก้ไข:
public class Line {
    private Point start, end;
    public Point getStart() {
      return start;
    }
}
การระบุประเภทการส่งคืนที่ไม่ถูกต้องจะทำให้เกิดข้อผิดพลาดทั้งระดับ โดยทั่วไปคอมไพลเลอร์จะรับรู้ข้อผิดพลาดเหล่านี้และรายงานเพื่อให้นักเรียนสามารถแก้ไขได้ด้วยตนเอง ผู้แต่ง: A. Grasoff™ อ่าน ลิงก์ต่อไปยังแหล่งที่มา: ข้อผิดพลาดของโปรแกรมเมอร์ Java มือใหม่
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION