TIL 2022-10-13 인터페이스마지막, 예외처리

JYR00·2022년 10월 13일
0

TIL

목록 보기
25/60

디폴트 메소드와 인터페이스 확장

디폴트 메소드와 인터페이스 확장 예제

MyInterface MyClassA MyClassB DefaultMethodEx
=> 디폴트메서드를 사용하는 이유

MyInterface

public interface MyInterface {
    public void method1(); // 인터페이스는 대부분 public 사용. 없어도 무방. 스스로추갛람
    default void method2(){
        System.out.println("dMyInterface의 method2() 실행");
    }
}

MyClassA

public class MyClassA implements MyInterface{ //상속
    @Override
    public void method1() { //MyInterface의 내용 구현함
        System.out.println("MyClassA의 method1()실행");
//        메서드1만 사용하다가 인터페이스가 업데이트되면 문제가 생김.
//        인터페이스는 상속을 받아 만드는 클래스가 반드시 있어야 한다.
//        뜬금없이 메서드2를 추가해야하는 상황이 됨 => 디폴트 메서드라는 개념생김
//        디폴트메서드가 되면 굳이 오버라이드 하지 않아도됨.
    }
    
    @Override
    public void method2(){
        System.out.println("MyclassA의 method2()실행"); 
//        원한다면 해도된다.(디폴트메서드)
    }
}

MyClassB

public class MyClassB implements MyInterface{
    @Override
    public void method1() {
        System.out.println("MyClassB의 method1()실행");
    }

    @Override
    public void method2() {
        System.out.println("MyClassB의 method2()실행");
    }
}

DefaultMethodEx

public class DefaultMethodEx {
    public static void main(String[] args) {
        MyInterface m1 = new MyClassA();
        m1.method1();
        m1.method2();

        MyInterface m2 = new MyClassB();
        m2.method1();
        m2.method2();
    }
}

활용 방법

  • 디폴트 메소드를 단순히 상속만 받음(위 예제)
  • 오버라이드(재정의)하여 실행내용변경(위 예제)
  • 추상메소드로 재선언 : 인터페이스가 상속받아 추상 메서드로 재정의하여 사용(아래 예제)

디폴트 메소드를 추상메서드로 재선언 예제

MyInterface2 MyClassC

MyInterface2

public interface MyInterface2 extends MyInterface{
//    인터페이스 간 상속은 extends 사용해야함

//    부모 인터페이스인 MyInterface에서 상속받은 멤버 메서드 중 디폴트 메서드인
//    method2()를 오버라이딩하여 추상 메서드로 변환.
//    Interface2를 상속받는 게 있다면 method2()를 무조건 오버라이딩해줘야한다.
    @Override
    void method2(); //디폴트메서드를 추상메서드로 받음

    void method3();
}

MyClassC

public class MyClassC implements MyInterface2{
    
    
    @Override
    public void method1() {
        System.out.println("MyClassC의 method1() 실행");
    }
//  1번. MyInterface에서 상속받은 추상메서드
    @Override
    public void method2() {
        System.out.println("MyClassC의 method2() 실행");
    }
//  2번. MyInterface에서 디폴트 메서드로 상속해줬으나 MyInterface2에서 추상메서드로 오버라이딩한 메서드
//    MyInterface2를 구현하는 구현체는 반드시 해당 메서드를 구현해야 함.
    @Override
    public void method3() {
        System.out.println("MyClassC의 method3() 실행");
    }
//    3번. MyInterface2에서 전용으로 생성한 추상메서드
}




캡슐화(private public get/set) 다형성 추상화. 뒤에 두 개가 어려운편.(특히 다형성)




💖10장 예외처리💖


오류 - 에러와 예외


에러 -> 관리되지 않은 오류

  • 하드웨어의 잘못된 동작 또는 고장으로 인한 오류
  • 프로그램 종료, 정상실행상태로 돌아갈 수 없다

예외 -> 관리되고 있는 오류

  • 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류
  • 프로그램 종료. 그러나 예외처리 추가하면 정상실행상태로 돌아갈 수 있음.

=> 마트의 고객센터

예외의 종류

  • 일반(컴파일 체크) 예외(Exception)

    • 예외 처리 코드 없으면 컴파일 오류 발생
  • 실행 예외(RuntimeException)

    • 예외 처리 코드를 생략하더라도 컴파일이 되는 예외
    • 경험에 따라 처리 코드 작성 필요
    • ex) 강제 형변환 (instaceof) 부모->자식.
      • 원본이 자식객체. 부모 -> 자식 // okay
      • 원본이 부모객체. 부모 -> 자식 // error(알맹이가 다르니)

예외 클래스

실행 예외

NullPointerException

  • 객체 참조가 없는 상태
  • null 값 갖는 참조변수로 개겣 접근 연산자인 도트(.)사용할 때 발생

ArrayIndexOutOfBoundsException

  • 배열에서 인덱스 범위 초과하여 사용할 경우 발생

ClassCastException

  • 타입 변환이 되지 않을 경우 발생

예외 예제

ExceptionEx -> chap03에 있다!

NullPointerException

public class ExceptionEx {
    public static void main(String[] args) {
        String data = null;
        System.out.println(data.toString()); //여기서는 말짱하지만 오류발생됨
    }
}

ArrayIndexOutOfBoundsException



String data1 = args[0];
String data2 = args[1];

System.out.println("args[0] : " + data1);
System.out.println("args[1] : " + data2);




NumberFormatException

String data1 = "100";
        String data2 = "a100"; //a 때문에 정수형 변형 불가.

        int value1 = Integer.parseInt(data1); // 문자형을 정수형으로 바꿔줌
        int value2 = Integer.parseInt(data2);

        int result = value1 + value2;
        System.out.println(data1 + "+" + data2 + "=" + result);

예외 처리 코드

try catch finally


try : 예외 발생 가능 코드
catch : 예외처리. (예외클래스 = Exception)

예외처리코드 예제

TryCatchEx

System.out.println("======NullPointerException========");
        try {
            String data = null;
            System.out.println(data.toString());
        }
        catch (Exception e){
            System.out.println("null인 데이터에서는 toString() 메서드를 사용할 수 없습니다.");
        }

        System.out.println("=====ArrayIndexOutOfBoundsException=======");
        try{
            String data1 = args[10]; //오류발생. 바로 catch로 넘어감. 이렇게하면 프로그램이 멈추지 않는다.
            String data2 = args[20];

            System.out.println("args[10] : " + data1);
            System.out.println("args[20] : " + data2);
        }
        catch (Exception e){
            System.out.println("배열의 최대 index 범위를 넘어서 사용하였습니다.");
        }

다중 catch

  • 예외 별로 예외 처리 코드 다르게 구현
  • 지정한 형식으로만 예외처리하고 싶을 때는 맞게 사용해야.
    TryCatchEx 여기에 들어있다.
System.out.println("=====다중 catch=======");
        try{
            String data1 = "100";
            String data2 = "a100";

            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);

            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
           
        }
  catch (NullPointerException e){
            System.out.println("null을 사용하여 진행할 수 없습니다.");
        }
        catch (NumberFormatException e){ //e는 Exception이 발생할 때 저장되는 데이터들을 넣어놨다.

            System.out.println("정수로 변환할 수 있습니다.");
            System.out.println(e.getMessage()); //For input string: "a100". 오류 왜났는지
            System.out.println(e.getStackTrace()); //[Ljava.lang.StackTraceElement;@1e643faf //주소
//            e.printStackTrace();// 에러와 관련된 정보를 전부 보여줌.
        }
//        Exception 클래스는 모든 예외 클래스의 최상위 클래스이므로 여러 개의 catch문을 사용할 경우
//        가장 마지막에 입력해야 한다.
        catch (Exception e){ //위에 있으면 Exception을 제외한 catch들을 오류로 표시.
            System.out.println("알 수 없는 오류가 발생했습니다.");
        }

멀티 catch


| 사용하여 or 처리.

finally

System.out.println("\n======finally 사용하기 =======");
        Scanner scanner = new Scanner(System.in);

        try{
            System.out.println("문자를 입력해주세요 : ");
            String data = scanner.nextLine();

            if(data.equals("")){
                data = null;
            }

//            System.out.println(data.toString());
            System.out.println("입력된 내용 : " + data.toString());
            System.out.println("여기는 정상 실행 완료 후 실행되는 부분입니다");
        }
        catch (NullPointerException e){
            System.out.println("여기는 예외 발생시 실행되는 부분입니다.");
            System.out.println("예외이유 : " + e.getMessage());
        }
        finally {
            System.out.println("여기는 무조건 실행되는 부분입니다.");
        }
        System.out.println("try ~ catch가 완료된 후 실행되는 부분입니다.");
    }
}

공백넣었을 때

문자넣었을 때

import java.io.*;
import java.util.Scanner;

public class TryCatchEx {
    public static void main(String[] args) throws FileNotFoundException {

//        String data = null;
//        System.out.println(data.toString());//현재 오류나는 부분(NullPointerException)

        System.out.println("======NullPointerException========");
        try {
            String data = null;
            System.out.println(data.toString());
        } catch (Exception e) {
            System.out.println("null인 데이터에서는 toString() 메서드를 사용할 수 없습니다.");
        }

        System.out.println("=====ArrayIndexOutOfBoundsException=======");
        try {
            String data1 = args[10]; //오류발생. 바로 catch로 넘어감. 이렇게하면 프로그램이 멈추지 않는다.
            String data2 = args[20];

            System.out.println("args[10] : " + data1);
            System.out.println("args[20] : " + data2);
        } catch (Exception e) {
            System.out.println("배열의 최대 index 범위를 넘어서 사용하였습니다.");
        }

        System.out.println("=====다중 catch=======");
        try {
            String data1 = "100";
            String data2 = "a100";

            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);

            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        }
//        예외처리를 하나로 모두 처리하면 Exception을 사용.
//        지정한 예외 상황만 처리하고자 하면 해당 예외 클래스를 사용해야 함.

//        catch (NumberFormatException e){
//            System.out.println("정수로 변환할 수 없습니다.");
//        }
//        catch (NullPointerException e){ //오류난다.
//            System.out.println("정수로 변환할 수 없습니다.");
//        }
//        catch (Exception e){
//            System.out.println("정수로 변환할 수 없습니다.");
//        }

//        하나의 try 구문에서 여러 개의 지정된 예외처리를 하고자 한다면 catch를 여러 개 사용할 수 있다.
        catch (NullPointerException e) {
            System.out.println("null을 사용하여 진행할 수 없습니다.");
        } catch (NumberFormatException e) { //e는 Exception이 발생할 때 저장되는 데이터들을 넣어놨다.

            System.out.println("정수로 변환할 수 있습니다.");
            System.out.println(e.getMessage()); //For input string: "a100". 오류 왜났는지
            System.out.println(e.getStackTrace()); //[Ljava.lang.StackTraceElement;@1e643faf //주소
//            e.printStackTrace();// 에러와 관련된 정보를 전부 보여줌.
        }
//        Exception 클래스는 모든 예외 클래스의 최상위 클래스이므로 여러 개의 catch문을 사용할 경우
//        가장 마지막에 입력해야 한다.
        catch (Exception e) { //위에 있으면 Exception을 제외한 catch들을 오류로 표시.
            System.out.println("알 수 없는 오류가 발생했습니다.");
        }

//        finally : try ~ catch 구문에서 예외가 발생하던 발생하지 않던 무조건 실행되어야 하는 소스코드를 입력하는
//        부분을 finally라고 한다. 주로 외부 리소스(파일, 네트워크 연결) 사용 시 해당 리소스를 해제하기 위한 목적으로 많이 사용함
//        자바의 가장 큰 특징 : 가비지 컬렉터 -> 비사용메모리 자동 정리. 파일, 네트워크 연결은 자동정리 안됨.
//        open만 하고 close를 안하면 계속 돌고 있다.

        System.out.println("\n======finally 사용하기 =======");
        Scanner scanner = new Scanner(System.in);

        try {
            System.out.println("문자를 입력해주세요 : ");
            String data = scanner.nextLine();

            if (data.equals("")) {
                data = null;
            }

//            System.out.println(data.toString());
            System.out.println("입력된 내용 : " + data.toString());
            System.out.println("여기는 정상 실행 완료 후 실행되는 부분입니다");
        } catch (NullPointerException e) {
            System.out.println("여기는 예외 발생시 실행되는 부분입니다.");
            System.out.println("예외이유 : " + e.getMessage());
        } finally {
            System.out.println("여기는 무조건 실행되는 부분입니다.");
        }
        System.out.println("try ~ catch가 완료된 후 실행되는 부분입니다.");

        System.out.println("\n\n ");


        File file = new File("test.txt");
        String str = "java file write test";

        try { //file 생성 -> 왼측에 있다.
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writer.write(str);
            writer.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println("파일 쓰기 사용 시 오류가 발생했습니다.");
        }
        System.out.println("파일 쓰기 완료");

        System.out.println("\n==== 파일 읽기 시작====");
        FileReader fr = null;
        BufferedReader reader = null;


        try {
            fr = new FileReader("c:\\test.txt"); //실제 파일 읽어온다(파일객체)
            reader = new BufferedReader(fr); // 실제 안의 내용 읽어옴

            String tmp;

            while ((tmp = reader.readLine()) != null){
                System.out.println("파일 내용 >> " + tmp); //안에 내용있다면 tmp에 저장
            }
        }
        catch (IOException e){
            System.out.println("파일 사용시 오류가 발생했습니다.");
            System.out.println(e.getMessage());
        }
        finally {
            try{
                if(reader != null) reader.close(); //닫는 순서 중요! 리더 -> 파일
                if(fr != null) reader.close();
            }
            catch (Exception e){

            }
        }
        System.out.println("=====파일 읽기 완료=======");
    }
}

try - with - resources

  • 예외 발생 여부와 상관없음
  • 사용했던 리소스 객체의 close() 메소드 호출해 리소스 닫음

자동 리소스 닫기

FileInputStream TryWithResourceEx

FileInputStream

public class FileInputStream implements AutoCloseable {
    private String file;

    public FileInputStream(String file){
        this.file = file;
    }
    public void read(){
        System.out.println(file + "을 읽습니다.");
    }
    @Override
    public void close() throws Exception{
        System.out.println(file + "을 닫습니다.");
    }
}

TryWithResourceEx

public class TryWIthResourceEx {
    public static void main(String[] args) {
//        이 방식으로만 해야 한다.
//        자동으로 메모리 해제
//        try with resources
        try (FileInputStream fis = new FileInputStream("file.txt")){
            fis.read();
            throw new Exception();  //예외 강제 발생
//            throw : 예외 자체를 사용자가 인위적으로만듦
        }
        catch (Exception e){
            System.out.println("예외처리 코드가 실행되었습니다.");
        }
        

예외 떠 넘기기

throw

  • 메서드 선언부 끝에 작성
  • 메서드에서 처리하지 않은 예외를 호출한 곳으로 떠 넘기는 역할
  • 원래는 안에서 다 처리해야 하는데, 다른 곳에서 예외처리해달라고 떠넘긴다.

throw 예제

Calculator ThrowsEx

Calculator

public class Calculator {
    public void sum(String a,String b){
        try{
            int result = 0;
            int num1 = Integer.parseInt(a);
            int num2 = Integer.parseInt(b);
            result = num1 + num2;
            System.out.println("두 수의 합은 : " + result + "입니다");
        }
        catch (Exception e){
            System.out.println("sum 함수에서 연산 시 오류가 발생했습니다.");
        }
    }
    
//    예외 발생 시 해당 메서드를 사용하는 곳으로 예외를 떠넘김
    public void sub(String a, String b) throws Exception{
        int num1 = Integer.parseInt(a); //오류가 발생할 가능성이 있는 소스
        int num2 = Integer.parseInt(b); //오류가 발생할 가능성이 있는 소스
        int result = num1 - num2;

        System.out.println("두 수의 차는 : " + result + "입니다.");
    }
}

ThrowsEx

public class ThrowsEx {
    public static void main(String[] args) {
        Calculator cal = new Calculator();


        try {
            cal.sum("십", "20"); //sum은 calculator에 오류처리부분이있다.
            cal.sub("10A", "20"); //실제 오류 발생한 부분은 calculator 클래스인데,
//            throw로 넘겼기 때문에 여기서 오류표시뜸. 이쪽에 정리하면 보기 편하다.
//            또한 예외처리를 따로 담당해주는 클래스를 만들 수 있다.
//            throw는 사용하는 곳에서 예외처리하게 만듦.
        }
        catch (Exception e){
            System.out.println("실행 시 오류가 발생했습니다.");
        }
    }
}

사용자 정의 예외

  • 자바 표준api에서 제공하지 않는 예외

예외 발생 시키기

우리가 임의적으로 조작하는 것.

// TryWithResoucrsEx에서 사용함
throw new Exception(); 

예외 발생 시키기 예제

BalanceInsufficientException, Account, AccountEx

BalanceInsufficientException

public class BalanceInsufficientException extends Exception{ // 상속받음
//    사용자 정의 예외
//    그냥 excti
    public BalanceInsufficientException(){} //기본생성자

    public BalanceInsufficientException(String message){ //생성자 오버로딩으로 여러 개 사용가능 
        super(message); //상속을 받았을 때 부모 클래스의 생성자를 가져오는 것. 받은 메세지를 exception에 넘겨줌
    }
}

Account

public void deposit(int money) { // 기존 금액, 새로 받은 금액 더해줌
        balance += money; // 이름이 다르니까 this붙일 필요 없다.
    }

    public void withdraw(int money) throws BalanceInsufficientException{ //매개 변수로 받아온 값 처리(money)
        if(balance < money){
//            예외처리가 없을 경우
//            System.out.println("출금 금액이 총 예금 금액보다 큽니다."); // 이렇게 하지 않아도 아래처럼 하면됨.

//            사용자 정의 예외를 사용함.
            throw new BalanceInsufficientException("잔고 부족 : " + (money - balance) + "원 모자람");
//            throw로 강제로 예외발생 -> new 매개변수로 메세지 발생.
//            원래 이곳에 try catch 해야함.
        }
        balance -= money;

//    try{
//        public void withdraw ( int money) throws BalanceInsufficientException { //매개 변수로 받아온 값 처리(money)
//        if (balance < money) {
//            throw new BalanceInsufficientException("잔고 부족 : " + (money - balance) + "원 모자람");
////            throw로 강제로 예외발생 -> new 매개변수로 메세지 발생.
////            원래 이곳에 try catch 해야함.
//        }
//        balance -= money;
//    }
//    catch(Exception e) {
//        System.out.println("dd");
//    }
    }
}

AccountEx

public class AccountEx {
    public static void main(String[] args) {
        Account account = new Account();

        account.deposit(10000);
        System.out.println("예금액 : " + account.getBalance());

        try{
            account.withdraw(30000);
        }
        catch (BalanceInsufficientException e){
            String message = e.getMessage(); //BalanceInsufficientException 에서 메세지 받아옴
            System.out.println(message); // 잔고 부족 : 20000원 모자람 이거 출력됨.
            System.out.println();
//            e.printStackTrace(); // 어디서 오류 났는지 정보 보여줌
//            e.getStackTrace();
        }
    }
}


예외 객체 e를 만들기 위해 존재.

위치를 정확히 알려주기 위해 throw를 사용.

getMessage()

  • 예외 발생시킬 때 생성자 매개값으로 사용한 메시지리턴
  • catch()절에서 활용

printStackTrace()

  • 예외 발생 코드 추적한 내용을 모두 콘솔에 출력
  • 개발자용. getStackTrace()는 주로 유지보수할 때 많이 쓰임.



컬랙션들어가기 전에 제네릭 간단하게 배우고 가자

제네릭 타입이란

  • 컴파일 단계에서 잘못된 타입 사용될 수 있는 문제 제거 가능.

제네릭 사용 이점

  • 컴파일 시 강한 타입 체크 가능
    • 미리 타입을 강하게 체크하여 에러 사전방지


추가 : add
뺄 때 : get
수정 : set

List list = new ArrayList();
모든 타입 넣을 수 있다. 그러므로 강제형변환 문자형으로 바꿔야한다.

제네릭은 <>안에 String을 넣음으로써 형을 미리 고정시켜놓는다.
뺄 때 get을 쓸 필요 없다.

<데이터타입>

제네릭 타입이란

컬렉션

  • 사전적 의미로 요소(객체)를 수집해 저장하는 것.
  • 배열의 문제점 :
    • 저장할 수 있는 객체 수가 배열 생성할 때 결정 -> 메모리가 낭비 혹은 모자를 수 있다.
    • 객체 삭제할 때 해당 인덱스가 비게 된다. -> 객체를 저장하려면 어디가 비어있는지 확인해야한다.(불편--^)

컬렉션 프레임워크

  • 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 제공하는 컬렉션 라이브러리

주요 인터페이스

List

ArrayList 많이 사용. 배열과 거의 유사. 중복된다. index

Map

HashMap 많이 사용. 중복저장이 안된다. key,value

Set

중복저장안됨.

List 컬렉션

  • 특징
    • 인덱스로 관리
    • 중복해서 객체 저장 가능
  • 구현 클래스
    • Arraylist
    • Vector
    • LinkedList


javascript의 배열과 자바의 리스트가 비슷하다.

ArrayList

배열 : 하나의 이름으로 동일한 타입의 데이터를 여러 개 저장하는 데이터 타입
ArrayList : 하나의 이름으로 동일한 타입의 데이터를 여러 개 저장하는 데이터 타입.
배열 : index 존재 (0부터 시작) 그러나 크기가 고정되어있다.
ArrayList : index 존재 (0부터 시작) 크기가 유동적이다.
=> 크기에 대한 차이를 제외하고는 모두 동일하다.

실제 현장에서는 배열보다는 ArrayList를 더 많이 사용한다.

ArrayList는 배열보다 속도는 느리지만 크기가 유동적이기에 보다 더 데이터를 효율적으로 사용할 수 있기 때문에 많이 사용되는 편이다.

ArrayList 예제

ArrayListEx

import java.util.ArrayList;
import java.util.List;
//import java.util.*; 이거 해도 됨


public class ArrayListEx {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(); //많이 사용하는 방식. 뒤의 <>에는 데이터타입 생략 가능.

        System.out.println("ArrayList 생성\nlist의 길이 : " + list.size()); // list.size()의 크기 알려줌

        list.add("HTML5");
        list.add("CSS3");
        list.add("Bootstrap5");
        list.add("JS ES6");
        list.add("React");
        list.add("Java");
        list.add("Servlet / JSP");
        list.add("Spring framework");
        list.add("Spring boot");
        list.add("Database(Mysql)");
        list.add("Python");

        System.out.println("\n데이터 추가 후 arraylist의 길이 확인 : " + list.size());
        // 데이터를 추가했기 때문에 arraylist가 11로 출력이 된다. 이게 바로 배열과 arraylist의 차이.

        String str = list.get(5); //5번째 것을 가져온다
        System.out.println("\nlist의 5번 index의 값 : " + str+"\n");

        System.out.println("리스트의 전체 내용 출력 ");

        for(int i =0; i<list.size(); i++){
            System.out.println("리스트 " + i + "번 index의 값 : " + list.get(i));
        }

        System.out.println("\n=====리스트 안 데이터 삭제하기======");

        list.remove(5); //5번 삭제
        list.remove(2); //2번 삭제
        list.remove("React"); //Java 삭제

        System.out.println("\nremove 후 list 변수의 크기 : " + list.size() + "\n");


        for(int i = 0; i < list.size(); i++){
            System.out.println("리스트" + i +"번 index값의 : " + list.get(i));
        }

//        List 클래스가 ArrayList의 부모이므로 부모 타입의 변수에 자식 클래스 타입인 ArrayList 객체를 대입하여 사용
//        List<String> list2 = new ArrayList<String>(); // 위 아래 중 원하는 방식으로 사용하면 된다
    }
}




































0개의 댓글