• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java 정리 26

18 Dec 2018

Reading time ~5 minutes

Java 정리 26 - Compile Exception, throws, 객체 복제, instanceof, throw, 사용자 정의 예외처리


Compile Exception

  • byte code를 정상적으로 생성하기 위한 것.
  • 개발자가 반드시 처리해야하는 예외.
public class UseCompileException {
  public static void main(String[] args) {
    try {
      Object obj =  Class.forName("java.lang.String1");
      
      System.out.println("로딩한 클래스 "+obj);
        
    } catch (ClassNotFoundException cnfe) {
      System.err.println("죄송합니다.");
      System.err.println("예외 메시지 출력 :  "+cnfe.getMessage());
      System.err.println("예외처리 객체와 메시지  : "+cnfe);
      
      // printStackTrace는 정보를 stack에 담고 출력하여
      // 시간이 조금 더 걸림(때문에 출력결과가 다른 out메시지가 먼저 출력가능)
      cnfe.printStackTrace();

      System.out.println("---");
      // out.println은 printStackTrace보다 먼저 출력
      // 순서대로 출력을 원할땐 err.println로 출력하면 된다
    }
  }
}

new없이 객체화

  • 외부에서 클래스 읽어들여서 바깥에서 객체화를 할 수 있다.
    • new 없이 객체화가 가능
    • 외부클래스 로딩할때 쓰는 메소드가 Class클래스의 forName 메소드
      • 클래스가 없으면 ClassNotFoundException 발생
try {
    Object obj =  Class.forName("java.lang.String");
    
    System.out.println("로딩한 클래스 "+obj);
    
} catch (ClassNotFoundException cnfe) {
    System.out.println("죄송합니다."); // 사용자에게 에러 메시지를 제공하지 않는다.
}
  • 시큐어 코딩가이드 227쪽 에러처리
    • 사용자에게 오류 메시지를 노출하지 않는다.
    • 운용할때는 printStackTrace는 모두 지운다(문자열처리)
    • try ~ catch문에서 catch 예외처리 블럭은 비워두지 않는다.

throws

  • 예외날림
  • method header 뒤에 정의
  • method 내에서 발생한 예외를 메소드를 호출한 곳에서 처리하도록 만드는 것
  • method내에서 try~catch를 할 필요가 없다.
    • 호출한 곳에서 try~catch로 처리한다.
    • 예외가 발생했을 때 처리코드를 업무로직에 대한 코드와 분리할 수 있다.
// 작성법
접근지정자 반환형 메소드명(매개변수,.. ) throws 예외처리클래스명,.. { ... }
// method내에서 발생한 예외를 method를 호출한 곳에서  처리하는 throws의 사용.
public class UseThrows {
  
  public void test() throws ClassNotFoundException {
    // throws로 예외를 날리면 method안에서  try~catch를 할 필요가 없다.
    String className =  "date181217.UseRuntimeException";
    
    if (new Random().nextBoolean()) {
      className = "java.long.Integer";
    }
    
    Object obj = Class.forName(className);
    System.out.println("클래스 로딩 "+obj);
      
  }
  
  public static void main(String[] args) {
                
    UseThrows ut = new UseThrows();
    try {
      // method를 호출하여 일 수행하다보면  문제가 발생할 수도 있다.
      ut.test();
    } catch (ClassNotFoundException cnfe) {
      System.err.println("죄송합니다.");
      cnfe.printStackTrace();
      System.out.println("정상출력");
    }
  }
}
  • 생성자에도 throws 사용가능
public class ConstructorThrows {
  public ConstructorThrows() throws  ClassNotFoundException {
    Class.forName("java.long.Object");
    System.out.println("객체생성");
  }
  
  public static void main(String[] args) {
    try {
      ConstructorThrows ct = new ConstructorThrows();
      System.out.println("객체화 성공 : "+ct);
    } catch (ClassNotFoundException cnfe) {
      System.err.println("객체화 중 예외발생");
      cnfe.printStackTrace();
    }
  }
}
public class ConstructorThrowsSub extends ConstructorThrows {
  // 부모클래스의 생성자가 컴파일 예외를 날리면 자식클래스
  // 생성자에서도 예외를 날려야 한다.
  public ConstructorThrowsSub() throws ClassNotFoundException {
    super();
    // super는 생성자의 첫번째 줄에서만 기술할 수  있음
    // 부모클래스의 생성자가 Compile Exception을  throws로 날리면
    // 생성자를 호출하는 자식생성자에서는 반드시  처리해야하는
    // 문법상 에러가 발생하게 된다.
    /*try {
      super(); // error!
    } catch (ClassNotFoundException cnfe) {
        
    }*/
  }
  public static void main(String[] args) { }
}

개체 복제

  • 모든 객체는 복제될 수 있는 method를 가지고 있다. (Object 클래스의 clone())
  • 변화된 상태를 저장해야하는 경우 객체를 복제
    • Stack, history기능을 구현할때 사용
    • call by reference로 그냥 복제안하고 한 객체를 여러번 push한다 한들 stack에서 pop하면 한개의 객체만 나오게 된다.
      • 복제해서 push하고 나중에 pop을 한다면 상태변화가 저장된 객체들을 사용가능.
  • Cloneable interface 구현한 객체만 복제된다.
  • 인스턴스변수가 없는 객체는 복제할 필요가 없다.

01

MyClass mc = new MyClass();
...
MyClass o1 = (MyClass)mc.clone(); // mc를 사용하다 현재 상태를 저장하고 싶을때 clone
// clone의 반환형은 Object, 부모는 자식을 모르기떄문에 형변환
// o1은 복제된 객체(저장된 시점에 mc의 상태를 저장한 객체)

// 복제가 안 될 수도 있을땐 try~catch로 예외처리
try {
    MyClass o2 = (MyClass)mc.clone();
} catch (CloneNotSupportedException cnse) {

}
public class ObjectClone implements Cloneable {
  
  private int i;
  public static void main(String[] args) {

    ObjectClone oc = new ObjectClone();
    oc.i = 100;
    
    try {
      // 현재 상태를 저장하기 위해 복제
      ObjectClone oc1 = (ObjectClone)oc.clone();
      System.out.println("복제성공 oc : "+oc+",  oc1 : "+oc1);

    } catch (CloneNotSupportedException cnse) {

      System.err.println("복제실패");
      cnse.printStackTrace();
    }
  }
}
  • 히스토리 처리
    • clone은 접근지정자가 protected이기 때문에 해당 클래스안에서 복제한걸 반환해줘야 한다.
public class Data implements Cloneable {
  private String school;
  public Data() {
    super();
  }
  public Data(String school) {
    this.school = school;
  }
  public String getSchool() {
    return school;
  }
  public void setSchool(String school) {
    this.school = school;
  }
  
  public Data getData() throws  CloneNotSupportedException {
    // clone()은 protected 접근지정자를 가지고  있어
    // 외부 클래스에서 다른 클래스의 clone()를  호출할 수 없다.
    Data data = (Data)this.clone();
    return data;
  }
}
public class DataClone {
  private Stack<Data> historyStack;
  
  public DataClone() {
    historyStack = new Stack<Data>();
  }
  
  public void useData() throws  CloneNotSupportedException {
    Data d = new Data("쌍용유치원");
    
    d.setSchool("쌍용초등학교");
    Data d1 = d.getData();
    historyStack.push(d1);
    
    d.setSchool("쌍용중학교");
    Data d2 = d.getData();
    historyStack.push(d2);
    
    d.setSchool("쌍용고등학교");
    Data d3 = d.getData();
    historyStack.push(d3);
    
    d.setSchool("쌍용대학교");
    Data d4 = d.getData();
    historyStack.push(d4);
    
    getHistoryData();
  }
  
  public void getHistoryData() {
    Data temp = null;
    while(!historyStack.isEmpty()) {
      temp = historyStack.pop();
      System.out.println(temp); // temp는 복제된  객체들, 주소가 다 다르다
      System.out.println(temp.getSchool());
    }
  }
  public static void main(String[] args) {
    try {
      new DataClone().useData();

    } catch (CloneNotSupportedException e) {

      System.err.println("복제되지 않습니다.");
      e.printStackTrace();
    }
  }
}

02


instanceof

  • 문자열로된 연산자
  • 생성된 객체가 특정 클래스로 부터 나왔는지 비교할 때 사용.
객체명 instanceof 클래스|인터페이스명; // boolean 반환

03

public interface Test {
  public String getData();
}

public class TestImpl implements Test {
  @Override
  public String getData() {
    return "2018-12-18";
  }
}

public class TestImpl1 implements Test {
  @Override
  public String getData() {
    SimpleDateFormat sdf = new  SimpleDateFormat("MM-dd-yyyy EEEE");
    return sdf.format(new Date());
  }
}

public class UseTest {
  public void useTest(Test test) {
      
    if (test instanceof TestImpl) {
      String date = test.getDate();
      System.out.println(date);
    } else {
      System.out.println("TestImpl만  처리합니다.");
    }
  }
  
  public static void main(String[] args) {
      
    UseTest ut = new UseTest();
    TestImpl ti = new TestImpl();
    TestImpl1 ti1 = new TestImpl1();
    
    ut.useTest(ti);
    ut.useTest(ti1);
  }
}

04


throw

  • 예외 강제 발생
  • 특정 조건에 일치하면 예외를 강제로 발생시켜 처리하는 것
  • 강제 발생된 예외는 반드시 try~catch로 처리하든 throws로 예외를 날리든 처리해야 한다.
  • 사용자정의 예외처리클래스와 주로 사용
throw new 예외처리클래스();

사용자 정의 예외처리

  • 업무에 맞는 예외처리 클래스가 없다면 그 예외처리 클래스를 만드는 것.
  • Exception을 상속받거나 Runtime Exception을 상속받아서 만든다.

05

// 사용자 정의 예외처리 클래스
// 1. Exception이나 RuntimeException을 상속받는다.
@SuppressWarnings("serial")
public class TobaccoException extends Exception {
  public TobaccoException() {
    this("담배예외 - 폐암의 원인 흡연! 그래도  피우시겠습니까?");
  }
  
  public TobaccoException(String msg) {
    super(msg);
  }
}
// 예외를 강제로 발생
public class TestThrow {
  
  // 길을 가다가 담배를 피우는 학생을 보면  정의사회를 구현한다.
  public void teacksung() throws TobaccoException {
      String[] grade = { "초등학생", "중학생",  "고등학생" };
      String randomGd = grade[new  Random().nextInt(grade.length)];
      
      if (randomGd.equals("초등학생")) {
          throw new TobaccoException();
      } else {
          System.out.println(randomGd+"이 담배를  피우면 모른척 지나간다. ('' )( '')");
      }
  }
  public static void main(String[] args) {
      
      TestThrow tt = new TestThrow();
      
      try {
          tt.teacksung();
      } catch (TobaccoException te) {
          te.printStackTrace();
      }
  }
}

06

  • RuntimeException을 상속받아 사용자 정의 예외클래스를 만들면 try~catch 안해도 된다.
    • 일반 Exception(Compile Exception)은 반드시 예외처리를 해야 함
public class TobaccoException extends RuntimeException {
...
// RuntimeException의 경우 try~catch나 throws를 안해도 됨
public void teacksung() { ...


Java