It's going to be one day 🍀

안녕하세요! 매일 매일 공부하려고 노력하는 백엔드 개발자 지망생의 공부 흔적입니다.

Back-End/Java # 교육

[Java 교육] 자동 리소스 닫기/중간정리/제네릭

2jin2 2024. 2. 8. 16:08

[공부 내용 정리]

자동 리소스 닫기(try-with-resource)

예외 발생 여부와 상관없이 리소스 객체의 close() 메소드를 호출해서 안전하게 리소스를 닫아줌.

  • Autocloseable 인터페이스의 close() 메소드를 직접 구현하는 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 + "을 닫습니다");
	}
}
public class TryWithResourceExample {
	
	public static void main(String[] args) {
		try (FileInputStream fileInputStream = new FileInputStream("file.txt")){
			fileInputStream.read();
			throw new Exception();		// 강제적으로 예외 발생시킴
		} catch (Exception e) {
			System.out.println("예외 처리 코드가 실행되었습니다.");
		}

	}
}

List 사용법

package chapter09;

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
//        List<Account> list = new ArrayList<>;
        List<String> list = new ArrayList<>();
        list.add("element1");
        list.add("element2");
        list.add("element3");
        System.out.println(list);
    }
}

→ add로 요소 추가 가능!!!

 

배열 코드 사용

  • 배열은 크기가 정해져 있으며, 크기를 초과하여 데이터를 추가하려면 새로운 배열을 생성하여 데이터를 복사해야함.
  • 배열의 요소를 추가하려면, 해당 인덱스에 값을 대입해야함.
  • 배열의 요소를 제거하려면, 해당 인덱스의 값을 삭제하고, 빈 자리를 채우기 위해 나머지 요소를 한 칸씩 앞으로 이동시켜야함.
  • // 배열 생성 int[] arr = new int[5]; // 값 추가 arr[0] = 1; arr[1] = 2; // 값 제거 arr[1] = 0; for (int i = 1; i < arr.length; i++) { arr[i-1] = arr[i]; } arr[arr.length-1] = 0;

리스트 코드 사용

  • 리스트는 크기가 가변적이며, 요소를 추가하거나 제거할 때마다 자동으로 크기가 조절됨.
  • 리스트의 요소를 추가하려면, add() 메서드 사용.
  • 리스트의 요소를 제거하려면, remove() 메서드 사용.
// 리스트 생성
List<Integer> list = new ArrayList<>();

// 값 추가
list.add(1);
list.add(2);

// 값 제거
list.remove(1);

 

배열과 리스트의 차이점

  • ex) 문제에서 n번이라는 크기가 정해졌을 때는 배열을 쓰고, 아무런 크기가 주어지지 않았을 땐 ArrayList를 사용함.
  • 따라서, 배열은 크기가 고정적이지만 인덱스를 통해 빠르게 요소에 접근할 수 있는 반면, 리스트는 크기가 가변적이지만 요소를 추가하거나 제거할 때 편리하게 사용할 수 있음.

제네릭

제네릭(generic)이란 데이터의 타입을 일반화(generalize)한다는 것.

→ 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 것.

  • 컴파일시 미리 타입이 정해지기 때문에, 타입 검사나 변환 같은 번거로운 작업을 생략할 수 있음.
  • 클래스나 메소드 내부에서 사용하는 타입 안정성을 높일 수 있음.

제네릭을 사용하는 이유

  1. 컴파일시 강한 타입 체크를 할 수 있음.
  • 컴파일시 미리 타입이 정해지기 때문에, 타입 검사나 변환 같은 번거로운 작업 생략 가능.
  • 타입 안정성을 높일 수 있음.
  1. 타입 변환(casting)을 제거함.
  • 불필요한 타입 변환을 할 필요가 없어서 성능이 향상됨.

ex)

ArrayList list2 = new ArrayList();
list2.add("str");
list2.add(1234);
list2.add(4.5);
String str3 = (String) list2.get(1);
String str4 = (String) list2.get(2);

→ 제네릭 사용 전 : 요소를 찾아올 때 String으로 타입 변환을 해야함

(list.get(0) 타입이 Object이기 때문)

ArrayList<String> list2 = new ArrayList();
list2.add("str");
list2.add("1234"); // 어차피 String인 요소만 들어감
list2.add("4.5");
String str3 = list2.get(1); 
String str4 = list2.get(2);

→ 제네릭 사용 후 : 요소를 찾아올 때 타입 변환을 할 필요가 없음!

 

제네릭 타입 (class<T>, Interface<T>)

제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스

public class 클래스명<T> { ... }
public interface 인터페이스명<T> { ... }

일반적으로 타입 파라미터는 T로 표현

ex)

package chapter09;

public class Box<T> {
    private T object;

    public T get() {
        return object;
    }
    public void set(T object) {
        this.object = object;
    }

}

→ Box.java

package chapter09;

public class BoxExample {
    public static void main(String[] args) {
        Box box = new Box();
        box.set("string");
//        String str = (String) box.get();
        Box<Integer> integerBox = new Box<>();
        integerBox.set(1234);
        Integer integer = integerBox.get();
        System.out.println(integer);

        Box<String> stringBox = new Box<>();
        stringBox.set("123문자열");
        String str = stringBox.get();
        System.out.println(str);
    }
}

→ BoxExample.java

이렇게 제네릭은 클래스를 설계할 때 구체적인 타입을 명시하지 않고, 타입 파라미터로 대체함. 그리고 실제 클래스가 사용될 때 구체적인 타입을 지정함으로써 타입 변환을 최소화시킴!!


Weekly Quiz

https://github.com/drinkgalaxy/Ormi-Task/tree/main/WeeklyQuiz/week3