JavaRush /Java Blog /Random-KO /초보 자바 프로그래머의 실수. 1 부
articles
레벨 15

초보 자바 프로그래머의 실수. 1 부

Random-KO 그룹에 게시되었습니다

1. 클래스명이 저장되어 있는 파일명과 다르다.

Javasoft JDK를 포함하여 내가 사용한 모든 Java 프레임워크는 public 수정자가 있는 클래스의 소스 코드가 클래스 이름과 정확히 동일한 이름 및 .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();
  }
}
참고:클래스 이름은 대문자로 시작한다고 가정합니다. 파일 이름에서 대소문자를 구분하는 운영 체제는 특히 DOS 파일 이름 지정 시스템에 익숙한 Unix에서 Java를 배우는 학생들에게 추가적인 문제를 일으킬 수 있습니다. 클래스는 MotorVehicle파일에 저장되어야 MotorVehicle.java하지만 motorvehicle.java.

2. 사용한 비교==

Java에서 문자열은 클래스의 객체입니다 java.lang.String. 객체에 적용된 연산자는 ==객체에 대한 참조가 동일한지 확인합니다! 때때로 학생들은 연산자의 의미를 이해하지 못하고 ==이를 사용하여 문자열을 비교하려고 합니다. 잘못된 예:
// проверим, equals ли первый аргумент "-a"
if (args[0] == "-a") {
    optionsAll = true;
}
두 문자열이 같은지 비교하는 올바른 방법은 equals()클래스 메서드를 사용하는 것입니다 java.lang.String. true문자열의 길이가 같고 동일한 문자를 포함하는 경우 반환됩니다 . (참고: 실제로 이는 동등성을 보장하지 않습니다. 실제로 equals두 문자열이 문자별로 동일한지 확인합니다.) 수정된 예:
//  проверим, equals ли первый аргумент "-a"
if ("-a".equals(args[0])) {
    optionsAll = true;
}
이 오류는 어리석은 일입니다. 왜냐하면 실제로 Java 코드는 구문론적으로는 정확하지만 결과적으로는 예상대로 작동하지 않기 때문입니다. 일부 학생들은 클래스 메서드 대신 비교 연산자 >및 를 사용하려고 합니다 . 이 오류는 컴파일 단계에서 오류를 일으키기 때문에 감지하기가 더 쉽습니다. <=compareTo()java.lang.String

3. 배열의 요소인 개체를 초기화하는 것을 잊었습니다.

Java에서 객체 배열은 실제로 객체 참조 배열입니다. 배열을 만드는 것은 단순히 아무 것도 가리키지 않는(즉, null인) 참조 집합을 만드는 것입니다. 실제로 개체의 "전체" 배열을 만들려면 배열의 각 요소를 초기화해야 합니다. 많은 학생들이 이것을 이해하지 못합니다. 그들은 객체 배열을 생성함으로써 자동으로 객체 자체를 생성한다고 믿습니다. (대부분의 경우 학생들은 이 개념을 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번 항목 참조) 학생들이 두 번째 규칙을 잊어버리는 경우가 있어 오류가 발생합니다. 무대 편집에서. 두 번째와 세 번째 규칙의 오류 메시지는 동일합니다(이것이 실제로 이 오류를 인식하기 어렵게 만드는 이유입니다).

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;
    }
}
이 오류를 해결하는 방법에는 여러 가지가 있습니다. 가장 간단한 방법은 암시적 포인터를 사용하여 클래스 필드에 액세스하는 것 입니다 this. this.Name_поля가장 좋은 방법은 클래스 필드나 지역 변수의 이름을 바꾸는 것입니다. 그러면 대체가 발생하지 않습니다. (대략 번역: 두 번째 방법은 우리의 방법이 아닙니다. 또한 언젠가 실수로 변수 필드를 교체하지 않을 것이라는 보장도 없습니다. 어떤 필드를 전혀 볼 수 없으면 상속에 더 큰 어려움이 발생합니다. 클래스에는 ) 수정된 예:
// 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)이는 일반적으로 생성자의 첫 번째 줄에 있는 메서드를 사용하여 슈퍼클래스 생성자를 호출함으로써 달성됩니다 . 생성자의 첫 번째 줄에 호출이 없으면 super(x)컴파일러 자체에서 매개변수 없이 이 호출을 삽입합니다 super(). (대략 번역: x...se, 하지만 몰랐습니다.) 때때로 학생들은 이 요구 사항을 잊어버립니다. 일반적으로 이것은 문제가 되지 않습니다. 슈퍼클래스 생성자에 대한 호출은 컴파일러에 의해 삽입되며 모든 것이 잘 작동합니다. 그러나 슈퍼클래스에 기본 생성자가 없으면 컴파일러에서 오류가 발생합니다. 아래 예에서 모든 슈퍼클래스 생성자에는 java.io.File1개 또는 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 블록이 발생할 수 있으며 컴파일러는 이를 지적합니다. 아래 예에는 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필요하지 않습니다 .) 학생들은 때때로 메소드를 호출하면 예외가 발생할 수 있다는 사실을 잊어버립니다. 이 문제를 해결하는 가장 쉬운 방법은 메서드 호출을 블록에 넣는 것입니다 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