728x90

Optional<T>

T타입 객체의 래퍼 클래스 - Optional<T>

public final class Optional<T> {
   private final T value; // T 타입의 참조변수
      ....
   }
}

NullPointerException 오류의 발생이 없고 if문 코드로 null을 체크 안 해줘도 되는 장점이 있다.

 

Optional<T> 객체를 생성하는 다양한 방법

String str = "abc";
Optional<String> optVal = Optional.of(str);
Optional<String> optVal = Optional.of("abc");
Optional<String> optVal = Optional.of(null); // NullpointerException 발생
Optional<String> optVal = Optional.ofNullable(null); // ok

null 대신 빈 Optional<T> 객체를 사용하자

Optional<String> optVal = null; // 널로 초기화 바람직하지 않음
Optional<String> optVal = Optional.<String>empty(); // 빈 객체로 초기화

Optional 객체의 값 가져오기

Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); // optVal에 저장된 값을 반환, null이면 예외발생
String str2 = optVal.orElse(" "); // optVal에 저장된 값이 null이면 " "반환
String str3 = optVal.orElseGet(String::new); // 람다식 사용가능
String str4 = optVal.orElseThrow(NullPointerException::new); // 널이면 예외발생

isPresent() - Optional 객체의 값이 null이면 false, 아니면 true를 반환

 

728x90
728x90

join()

지정된 시간 동안 특정 스레드가 작업하는 것을 기다린다.

예외처리를 해야 된다.(InterruptedException이 발생하면 작업 재개)

 

yield()

남은 시간을 다음 쓰레드에게 양보하고, 자신(현재 스레드)은 실행 대기한다.

yield()와 interrupt()를 적절히 사용하면, 응답성과 효율을 높일 수 있다.

 

스레드의 동기화

멀티 쓰레드 프로세스에서는 다른 쓰레드의 작업에 영향을 미칠 수 있다.

진행 중인 작업이 다른 스레드에게 간섭받지 않게 하려면 동기화가 필요

동기화하려면 간섭받지 않아야 하는 문장들을 임계 영역으로 설정

임계 영역은 락을 얻은 단 하나의 스레드만 출입가능(객체 1개에 락 1개)

 

synchronized를 이용한 동기화

synchronized로 임계 영역(lock이 걸리는 영역)을 설정하는 방법 2가지

1. 메서드 전체를 임계 영역으로 지정
public sychronized void calcsum() {
   // ...             임계 영역
}
2. 특정한 영역을 임계 영역으로 지정
sychronized(객체의 참조변수) {
   // ...             임계 영역
}

wait()과 notify()

동기화 효율을 높이기 위해 wait(), notify()를 사용

Object클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할 수 있다.

  • wait() - 객체의 lock을 풀고 스레드를 해당 객체의 waiting pool에 넣는다.
  • notify() - waiting pool에서 대기 중인 쓰레드 중의 하나를 깨운다.
  • notifyAll() - waiting pool에서 대기중인 모든 스레드를 깨운다.

람다식

함수(메서드)를 간단한 식으로 표현하는 방법

익명 함수(이름이 없는 함수, anonymous function)

함수와 메서드의 차이

  • 근본적으로 동일. 함수는 일반적 용어, 메서드는 객체지향 개념 용어
  • 함수는 클래스에 독립적, 메서드는 클래스에 종속적

람다식 작성하기

  1. 메서드의 이름과 반환 타입을 제거하고 '->'를 블록{ } 앞에 추가한다.
  2. 반환 값이 있는 경우, 식이나 값만 적고 return문 생략 가능(끝에 ; 안 붙임)
  3. 매개변수의 타입이 추론 가능하면 생략 가능(대부분의 경우 생략 가능)

람다식 작성하기 - 주의 사항

  1. 매개변수가 하나인 경우, 괄호() 생략 가능(타입이 없을 때만)
  2. 블록 안의 문장이 하나뿐 일 때, 괄호 { } 생략 가능(끝에 ; 안 붙임)
  3. 단 하나뿐인 문장이 return문이면 괄호 { } 생략 불가

람다식은 익명 함수가 아니라 익명 객체이다.

 

함수형 인터페이스

함수형 인터페이스 - 단 하나의 추상 메서드만 선언된 인터페이스

함수형 인터페이스 타입의 참조 변수로 람다식을 참조할 수 있음(단, 함수형 인터페이스의 메서드와 람다식의 매개변수 개수와 반환 타입이 일치해야 함)

 

생성자와 메서드 참조

콜론 두 개 (:: – 이중 콜론 연산자)의 정식 명칭은 메서드 참조 표현식(method reference expression)이며, 결론부터 말하자면 람다식에서 파라미터를 중복해서 쓰기 싫을 때 사용합니다.

람다 표현식(expression)에서만 사용 가능하고, 사용 방법은 [인스턴스]::[메서드명(또는 new)]

Supplier<MyClass> s = () -> new MyClass();
Supplier<Myclass> s = MyClass::new;

 

스트림

다양한 데이터 소스를 표준화된 방법으로 다루기 위한 것

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> intStream = list.stream(); // 컬렉션
Stream<String> strStream = Stream.of(new String[] {"a", "b", "c"}); // 배열
Stream<Integer> evenStream = Stream.iterate(0, n -> n + 2); // 0, 2, 4, 6, ...
Stream<Double> randomStream = Stream.generate(Math::random); // 람다식
IntStream intStream = new Random().ints(5); // 난수 스트림(크기가 5)

스트림

스트림이 제공하는 기능 - 중간 연산과 최종 연산

  • 중간 연산 - 연산 결과가 스트림인 연산. 반복적으로 적용 가능
  • 최종 연산 - 연산 결과가 스트림이 아닌 연산. 단 한 번만 적용 가능(스트림의 요소를 소모)

Stream.distinct(). limit(5). sorted(). forEach(System.out::println)

. distinct() : 중간 연산,. limit(5) : 중간 연산,. sorted() : 중간 연산,. forEach(System.out::println) : 최종 연산

스트림은 데이터 소스로부터 데이터를 읽기만 할 뿐 변경하지 않는다.

스트림은 Iterator처럼 일회용이다.(필요하면 다시 스트림을 생성해야 함)

최종 연산 전까지 중간 연산이 수행되지 않는다. - 지연된 연산

 

 

728x90
728x90

열거형

관련된 상수들을 같이 묶어 놓은 것. Java에는 타입에 안전한 열거형을 제공

열거형 정의 방법

  • enum 열거형 이름 { 상수명 1, 상수명 2,...}

열거형 상수의 비교는 == 과 compareTo() 사용 가능

모든 열거형은 Enum의 자손이며, 아래의 메서드를 상속받는다.

메서드 설명
Class<E> getDeclaringClass() 열거형의 class 객체를 반환
String name() 열거형 상수의 이름을 문자열로 반환
int ordinal() 열거형 상수가 정의된 순서를 반환(0부터 시작)
T valueOf(Class<T> enumType, String name) 지정된 열거형에서 name과 일치하는 열거형 상수를 반환

불연속적인 열거형 상수의 경우, 원하는 값을 괄호() 안에 적는다.

  • enum Direction { EAST(1), SOUTH(5), WEST(-1)}

괄호를 사용하려면, 인스턴스 변수와 생성자를 새로 추가해 줘야 한다.

enum Direction {
  EAST(1), SOUTH(5), WEST(-1);
  private final int value; // 정수를 저장할 필드(인스턴스 변수)를 추가
  Direction(int value) {
     this.vlaue = value;  // 생성자를 추가
  }
  public int getValue() {
     return value;
  }
}

열거형의 생성자는 묵시적으로 private이므로, 외부에서 객체 생성 불가

 

메타 애너테이션

메타 애너테이션은 애너테이션을 위한 애너테이션

메타 에너테이션은 java.lang.annotation 패키지에 포함

애너테이션 설명
@Target 애너테이션이 적용가능한 대상을 지정하는데 사용
@Documented 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
@Inherited 애너테이션 자손 클래스에 상속되도록 한다.
@Retention 애너테이션이 유지되는 범위를 지정하는데 사용한다.
@Repeatable 애너테이션을 반복해서 적용할 수 있게 한다.

@Target

대상 타입 의미
ANNOTATION_TYPE 애너테이션
CONSTRUCTOR 생성자
FIELD 필드(맴버변수, enum상수)
LOCAL_VARIABLE 지역변수
METHOD 메서드
PACKAGE 패키지
PARAMETER 매개변수
TYPE 타입(클래스, 인터페이스, enum)
TYPE_PARAMETER 타입 매개변수
TYPE_USE 타입이 사용되는 모든 곳

@Retention

유지 정책 의미
SOURCE 소스 파일에만 존재, 클래스파일에는 존재하지 않음
CLASS 클래스 파일에 존재, 실행시 사용 불가 , 기본 값
RUNTIME 클래스 파일에 존재, 실행시에 사용 가능

컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.

실행 시에 사용 가능한 애너테이션의 정책은 RUNTIME이다.

 

프로세스

실행 중인 프로그램, 자원과 스레드로 구성

 

쓰레드

프로세스 내에서 실제 작업을 수행

모든 프로세스는 최소한 하나의 스레드를 가지고 있다.

 

멀티 스레드의 장단점

장점

  • 시스템 자원을 보다 효율적으로 사용할 수 있다.
  • 사용자에 대한 응답성이 향상된다.
  • 작업이 분리되어 코드가 간결해진다.

단점

  • 동기화에 주의해야 한다.
  • 교착상태가 발생하지 않도록 주의해야 한다.
  • 각 스레드가 효율적으로 고르게 실행될 수 있게 해야 한다. 

쓰레드 구현과 실행

  1. Thread 클래스를 상속
  2. Runnable 인터페이스를 구현

스레드의 실행

스레드를 생성한 후에 start()를 호출해야 쓰레드가 작업을 시작한다.

ThreadEx1_1 t1 = new ThreadEx1_1(); // 쓰레드 t1을 생성한다.
ThreadEx1_1 t2 = new ThreadEx1_1(); // 쓰레드 t2을 생성한다.

t1.start(); // 쓰레드 t1을 실행시킨다.
t2.start(); // 쓰레드 t2를 실행시킨다.

 

main 쓰레드

main 메서드의 코드를 수행하는 쓰레드

스레드는 사용자의 쓰레드와 데몬 쓰레드 두 종류가 있다.

 

스레드의 우선순위

작업의 중요도에 따라 스레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할 수 있다.

setPriority(숫자);

 

쓰레드 그룹

서로 관련된 스레드를 그룹으로 묶어서 다루기 위한 것

모든 스레드는 반드시 하나의 쓰레드 그룹에 포함되어 있어야 한다.

쓰레드 그룹을 지정하지 않고 생성한 쓰레드는 main 쓰레드 그룹에 속한다.

자신을 생성한 스레드(부모 쓰레드)의 그룹과 우선순위를 상속받는다.

 

데몬 쓰레드

일반 스레드의 작업을 돕는 보조적인 역할을 수행

일반 스레드가 모두 종료되면 자동적으로 종료된다.

가비지 컬렉터, 자동 저장, 화면 자동갱신 등에 사용된다.

무한루프와 조건문을 이용해서 실행 후 대기하다가 특정 조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다.

boolean isDaemon() - 스레드가 데몬 스레드인지 확인한다.

void setDaemon(boolean on) - 스레드를 데몬 스레드로 또는 사용자 쓰레드로 변경, 매개변수 on을 true로 지정하면 데몬 스레드가 된다.

setDaemon(boolean on)은 반드시 start()를 호출하기 전에 실행되어야 한다. 그렇지 않으면 IllegalThreadStateException이 발생한다.

 

스레드의 상태

상태 설명
NEW 쓰레드가 생성되고 아직 start()가 호출되지 않은 상태
RUNNABLE 실행 중 또는 실행 가능 상태
BLOCKED 동기화블럭에 의해서 일시정지된 상태(lock이 풀릴 때까지 기다리는 상태)
WAITING, TIMED_WAITING 쓰레드의 작업이 종료되지는 않았지만 실행가능하지 않은(unrunnable) 일시정지 상태. TIMED_WAITING은 일시정지시간이 지정된 경우를 의미
TERMINATED 쓰레드의 작업이 종료된 상태

 

sleep()

현재 스레드를 지정된 시간 동안 멈추게 한다.

예외처리를 해야 한다.(InterruptedException이 발생하면 깨어남)

 

interrupt()

대기상태인 스레드를 실행 대기 상태로 만든다.

 

 

728x90
728x90

HashSet

객체를 저장하기 전에 기존에 같은 객체가 있는지 확인

같은 객체가 없으면 저장하고, 있으면 저장하지 않는다.

 

TreeSet

이진 탐색 트리로 구현. 범위 탐색과 정렬에 유리

이진트리는 모든 노드가 최대 2개의 하의 노드를 갖는다.

각 요소(Node)가 나무 형태로 연결

 

이진 탐색 트리

부모보다 작은 값은 왼쪽 큰 값은 오른쪽에 저장

데이터가 많아질수록 추가, 삭제에 시간이 더 걸림

 

HashMap

Map인터페이스를 구현한 대표적인 컬렉션 클래스

순서를 유지하려면, LinkedHashMap클래스를 사용하면 된다.

해싱 기법으로 데이터를 저장, 데이터가 많아도 검색이 빠르다.

Map인터페이스를 구현. 데이터를 키와 값의 쌍으로 저장

 

TreeMap

범위 검색과 정렬에 유리한 컬렉션 클래스

HashMap보다 데이터 추가, 삭제에 시간이 더 걸림

 

제네릭

컴파일 시 타입을 체크해 주는 기능

객체의 타입 안정성을 높이고 형 변환의 번거로움을 줄여줌

참조 변수와 생성자의 대입된 타입은 일치해야 한다.

ArrayList<Tv> list = new ArrayList<Tv>(); // ok
ArrayList<Product> list = new ArrayList<Tv>(); // error

제네릭 클래스 간의 다형성은 성립

List<Tv> list = new ArrayList<Tv>(); // ok
List<Tv> list = new LinkedList<Tv>(); // ok

매개변수의 다형성도 성립

extends로 대입할 수 있는 타입을 제한

 

제네릭 용어

Box <T> 제네릭 클래스 'T의 Box' 또는 'T Box'라고 읽는다.

T 타입 변수 또는 타입 매게 변수 (T는 타입 문자)

Box 원시 타입

 

제네릭 제약

타입 변수에 대입은 인스턴스 별로 다르게 가능

static 멤버에 타입 변수 사용 불가

배열 생성할 때 타입 변수 사용불가. 타입 변수로 배열 선언은 가능

 

와일드카드

하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

<? extends T> : 와일드카드의 상한 제한 T와 그 자손들만 가능

<? super T> : 와일드 카드의 하한 제한 T와 그 조상들만 가능

<?> : 제한 없음. 모든 타입이 가능 

 

 

728x90
728x90

컬렉션

여러 객체(데이터)를 모아놓은 것을 의미

 

프레임웍

표준화 정형화된 체계적인 프로그래밍 방식

 

컬렉션 프레임웍

컬렉션(다수의 객체)을 다루기 위한 표준화된 프로그래밍 방식

컬렉션을 쉽고 편리하게 다룰 수 있는 다양한 클래스를 제공

java.util 패키지에 포함

 

1. List

순서가 있는 데이터의 집합. 데이터의 중복을 허용한다.

구현 클래스 : ArrayList, LinkedList, Stack, Vector 등

2. Set

순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않는다.

구현 클래스 : HashSet, TreeSet 등

3. Map

키와 값의 쌍으로 이루어진 데이터의 집합

순서는 유지되지 않으며, 키는 중복을 허용하지 않고, 값은 중복을 허용한다.

구현 클래스 : HashMap, TreeMap, HashTable, Propertise 등

 

ArrayList

ArrayList는 기존의 Vector를 개선한 것으로 구현원리와 기능적으로 동일

ArrayList와 달리 Vector는 자체적으로 동기화 처리가 되어있다.

List인터페이스를 구현하므로, 저장순서가 유지되고 중복을 허용한다.

데이터의 저장공간으로 배열을 사용한다.

 

ArrayList에 저장된 객체의 삭제과정

  1. 삭제할 데이터 아래의 데이터를 한 칸씩 위로 복사해서 삭제할 데이터를 덮어쓴다.
  2. 데이터가 모두 한 칸씩 이동했으므로 마지막 데이터는 null로 변경한다.
  3. 데이터가 삭제되어 데이터의 개수가 줄었으므로 size를 감소시킨다.

배열의 장점

배열은 구조가 간단하고 데이터를 읽는 데 걸리는 시간이 짧다

배열의 단점

크기를 변경할 수 없다. 크기를 변경해야 하는 경우 새로운 배열을 생성 후 데이터를 복사해야 함

비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다.

 

LinkedList 

배열과 달리 LinkedList는 불연속적으로 존재하는 데이터를 연결

데이터의 삭제 : 단  한 번의 참조 변경만으로 가능

데이터의 추가 : 한 번의 Node객체 생성과 두 번의 참조 변경만으로 가능

순차적으로 데이터 추가/삭제 : ArrayList가 빠름

비순차적으로 데이터 추가/삭제 : LinkedList가 빠름

접근 시간 : ArrayList가 빠름

 

Comparable : 기본 정렬 기준을 구현하는데 사용

Comparator : 기본 정렬기준 외의 다른 기준으로 정렬하고자 할 때 사용

compare()와 compareTo()는 두 개체의 비교 결과를 반환하도록 작성 

 

HashSet

set인터페이스를 구현한 대표적인 컬렉션 클래스

순서를 유지하려면, LinkedHashSet클래스를 사용하면 된다.

 

TreeSet

범위 검색과 정렬에 유리한 컬렉션 클래스

HashSet보다 데이터 추가, 삭제에 시간이 더 걸림

728x90
728x90

연결된 예외

한 예외가 다른 예외를 발생시킬 수 있다.

예외 A가 예외 B를 발생시키면, A는 B의 원인 예외

Throwable initCause(Throwable cause) // 지정한 예외를 원인 예외로 등록
Throwable getCause() // 원인 예외를 반환

 

사용하는 이유

  1. 여러 예외를 하나로 묶어서 다루기 위해서
  2. checked 예외를 unchecked 예외로 변경하려고 할 때

hashcode()

객체의 해시 코드를 반환하는 메서드

Object클래스의 hashCode()는 객체의 주소를 int로 변환해서 반환

equals()를 오버 라이딩하면, hashCode()도 오버 라이딩해야 한다.

equals()의 결과가 true인 두 객체의 해시코드는 같아야 하기 때문

 

toString()

객체를 문자열으로 변환하기 위한 메서드

 

String(char[] value) 메서드

주어진 문자열을 갖는 String 인스턴스를 생성한다.(문자 배열을 문자열로 바꿔준다.)

char c[] = {'H', 'E', 'L', 'L', 'O'};
String s = new String(c);
==================================
s = "HELLO"

int compareTo(String str)

문자열과 사전순서로 비교한다. 같으면 0을, 사전 순으로 이전이면 음수를, 이후면 양수를 반환

int i = "aaa".compareTo("aaa");
int i2 = "aaa".compareTo("bbb");
int i3 = "bbb".compareTo("aaa");
================================
i = 0, i2 = -1, i3 = 1

boolean contains(charSequence s)

지정된 문자열이 포함되어 있는지 검사

String s = "abcdefg";
boolean b = s.contains("bc");
=============================
b = true

boolean endsWith(String suffix)

지정된 문자열(suffix)로 끝나는지 검사한다.

String file = "Hello.txt";
boolean b = file.endsWith("txt");
=================================
b = true

boolean equalsIgnoreCase(String str)

문자열과 String인스턴스의 문자열을 대소문자 구분없이 비교한다.

String s = "Hello";
boolean b = s.equalsIgnoreCase("HELLO");
boolean b2 = s.equalsIgnoreCase("heLLO");
=========================================
b = true, b2 = true

int indexOf(int ch), int indexOf(int ch, int pos)

주어진 문자(ch)가 문자열에 존재하는지 확인하여 위치(index)를 알려준다. 못 찾으면 -1을 반환한다.

 

String s = "Hello";
int idx = s.indexOf('o');
int idx2 = s.indexOf('k');
int idx3 = s.indexOf('e', 0);
int idx4 = s.indexOf('e', 2);
=========================================
idx = 4, idx2 = -1, idx3 = 1, idx4 = -1

String[] split(String regex), String[] split(String regex, int limit) 

문자열을 지정된 분리자(regex)로 나누어 문자열 배열에 담아 반환한다.

String animal = "dog,cat,bear");
String[] arr = animal.split(",");
String[] arr2 = animal.split(",", 2);
===============================================
arr[0] = "dog", arr[1] = "cat", arr[2] = "bear"
arr2[0] = "dog", arr2[1] = "cat,bear"

String substring(int begin) String substring(int begin, int end)

주어진 시작위치(begin)부터 끝 위치(end) 범위에 포함된 문자열을 얻는다. 이때 시작 위치의 문자는 범위에 포함되지만, 끝 위치의 문자는 포함되지 않는다.

String s = "java.lang.Object";
String c = s.substring(10);
String p = s.subString(5, 9);
=================================
c = "Object", p = "lang"

String trim()

문자열의 왼쪽 끝과 오른쪽 끝에 있는 공백을 없앤 결과를 반환한다. 이 때 문자열 중간의 공백은 제거되지 않는다.

String s = "  Hello World  ";
String s1 = s.trim();
===============================
s1 = "Hello World"

join()

여러 문자열 사이에 구분자를 넣어서 결합한다.

String animal = "dog,cat,bear";
String[] arr = animal.split(",");
String str = String.join("-", arr);
System.out.println(str);
====================================
str = dog-cat-bear

StringBuffer 클래스

String 처럼 문자형 배열(char[])을 내부적으로 가지고 있다.

그러나 String과 달리 내용을 변경할 수 있다.

append()는 지정된 내용을 StringBuffer에 추가 후, StringBuffer의 참조를 반환

StringBuffer는 equals()가 오버라이딩되어있지 않다.

StringBuffer를 String으로 변환 후에 equals()로 비교해야 한다.

StringBuffer sb = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb == sb2) // false
System.out.println(sb.equals(sb2)) // false
================================================
String s = sb.toString();
String s2 = sb.toString();
System.out.println(s.equals(s2)) // true

StringBuilder

StringBuilder는 동기화되어 있다. 멀티 스레드에 안전(thread-safe)

멀티 쓰레드 프로그램이 아닌 경우, 동기화는 불필요한 성능 저하 이럴 땐 StringBuffer 대신 StringBuilder를 사용하면 성능 향상

 

static int abs(int f)

주어진 값의 절댓값을 반환한다.

int i = Math.abs(-10);
======================
i = 10

static double ceil(double a)

주어진 값을 올림하여 반환한다.

double d = Math.ceil(10.1);
============================
d = 11.0

static double floor(double a)

주어진 값을 버림하여 반환한다.

double d = Math.floor(10.8);
double d2 = Math.floor(-10.8);
===============================
d = 10.0, d2 = -11.0

static long round(float a)

소수점 첫째자리에서 반올림한 정수 값(long)을 반환한다. 두 정수중 가운데 있는 값은 항상 큰 정수를 반환

 

래퍼(wrapper) 클래스

8개의 기본형을 객체로 다뤄야 할 때 사용하는 클래스

기본형 첫 글자를 대문자로 바꾸면 됨

래퍼 클래스는 모두 equals()가 오버 라이딩되어 있어서 주소가 아닌 객체 값을 비교한다.

 

728x90
728x90

인터페이스를 이용한 다형성

인터페이스 타입 매개변수는 인터페이스 구현한 클래스의 객체만 가능

인터페이스를 메서드의 리턴 타입으로 지정할 수 있다.

 

인터페이스의 장점

  • 두 대상(객체)간의 연결, 대화, 소통을 돕는 중간 역할을 한다.
  • 선언(설계)과 구현을 분리시킬 수 있게 한다.
  • 인터페이스 덕분에 B가 변경되어도 A는 안 바꿀 수 있게 된다.
  • 개발 시간을 단축할 수 있다.
  • 변경에 유리한 유연한 설계가 가능하다.
  • 표준화가 가능하다.
  • 서로 관계없는 클래스들을 관계를 맺어줄 수 있다.

디폴트 메서드와 static메서드

인터페이스에 디폴트 메서드, static 메서드 추가 가능(jdk 1.8부터)

인터페이스에 새로운 메서드(추상 메서드)를 추가하기 어려움 -> 디폴트 메서드 생성

디폴트 메서드는 인스턴스 메서드(인터페이스 원칙 위반)

interface MyInterface {
	void method();
    void newMethod(); // 추상 메서드
}

해결책
interface MyInterface {
	void method();
    default void newMethod() {}
}

디폴트 메서드가 기존의 메서드와 충돌할 때의 해결책

1. 여러 인터페이스의 디폴트 메서드 간의 충돌

인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.

2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌

조상클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

 

내부 클래스

클래스 안에 클래스

 

내부 클래스의 장점

내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.

코드의 복잡성을 줄일 수 있다.(캡슐화)

내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일

 

프로그램 오류

컴파일 에러 : 컴파일 할 때 발생하는 오류

런타임 에러 : 실행 할 때 발생하는 오류

논리적 에러 : 작성 의도와 다르게 동작

 

Java 런타임 에러

에러 : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류

예외 : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류

 

예외처리의 정의와 목적

정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것

목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

 

Exception 클래스 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외

RuntimeException 클래스 : 프로그래머의 실수로 발생하는 예외

 

try-catch 문에서의 흐름

1. try블럭 내에서 예외가 발생한 경우

  1. 발생한 예외와 일치하는 catch 블록이 있는지 확인한다.
  2. 일치하는 catch 블럭을 찾게 되면 그 catch 블록 내의 문장들을 수행하고 전체 try - catch 문을 빠져나가서 그다음 문장을 계속해서 수행한다. 만일 일치하는 catch 블록을 찾지 못하면 예외는 처리되지 못한다.

2. try 블럭 내에서 예외가 발생하지 않은 경우

  1. catch 블럭을 거치지 않고 전체 try-catch 문을 빠져나가서 수행을 계속한다.

printStackTrace() : 예외 발생 당시의 호출 스택에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.

getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.

 

checked 예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수 : Exception)

unchecked 예외 : 컴파일러가 예외 처리 여부를 체크 안 함(예외 처리 선택 : RuntimeException) 

 

예외를 처리하는 방법

try-catch문, 예외 선언하기

 

예외 선언

메서드가 호출시 발생 가능한 예외를 호출하는 쪽에 알리는 것 

 

finally 블럭

예외 발생 여부와 관계없이 수행되어야 하는 코드를 넣는다.

try-catch 문 제일 마지막에 위치해야 한다.

 

사용자 정의 예외 만들기

우리가 직접 예외 클래스를 정의할 수 있다.

조상은 Exception과 RuntimeException 중에서 선택

 

 

728x90
728x90

제어자

클래스와 클래스의 맴버(맴버 변수, 메서드)에 부가적인 의미 부여

  • 접근 제어자 : public, default, protected, private 
  • 그 외 : static, final, abstract, native, transient, 등

final

  • 클래스 : 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다. 그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
  • 메서드 : 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
  • 맴버변수, 지역변수 : 변수 앞에 final이 붙으면, 값을 변경할 수 없는  상수가 된다.

abstract

  • 클래스 : 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
  • 메서드 : 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.

접근 제어자

  • private : 같은 클래스 내에서만 접근이 가능하다.
  • default : 같은 패키지 내에서만 접근이 가능하다.
  • protected : 같은 패키지 내에서 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
  • public : 접근 제한이 전혀 없다.

캡슐화와 접근 제어자

접근 제어자를 사용하는 이유 

  • 외부로부터 데이터를 보호하기 위해
  • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서

다형성

  • 여러가지 형태를 가질 수 있는 능력
  • 조상 타입 참조 변수로 자손 타입 객체를 다루는 것
  • 자손 타입의 참조 변수로 조상 타입의 객체를 가리킬 수 없다.

참조변수의 형변환

  • 사용할 수 있는 맴버의 개수를 조절하는 것
  • 조상 자손 관계의 참조변수는 서로 형변환 가능

instanceof 연산자

  • 참조변수의 형변환 가능여부 확인에 사용. 가능하면 true 반환
  • 형변환 전에 반드시 instanceof로 확인해야 함

매개변수의 다형성

참조형 매개변수는 메서드 호출 시, 자신과 같은 타입 또는 자손 타입의 인스턴스를 넘겨줄 수  있다.

 

추상 클래스

  • 미완성 설계도, 미완성 메서드를 갖고 있는 클래스
  • 다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가
  • 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능

추상 메서드

  • 미완성 메서드. 구현부 {} 없는 메서드
  • 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우

추상 클래스의 작성

여러 클래스에 공통적으로 사용될 수 있는 추상 클래스를 바로 작성하거나 기존 클래스의 공통 부분을 뽑아서 추상클래스를 만든다.

추상화된 코드는 구체화된 코드보다 유연하다. 변경에 유리

 

인터페이스

  • 추상 메서드의 집합
  • 구현된 것이 하나도 없는 설계도, 껍데기(모든 맴버가 public)
  • 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상은 아님)
  • 다중 상속이 가능 

인터페이스의 구현

  • 인터페이스에 정의된 추상 메서드를 완성하는 것
  • 일부만 구현하는 경우 클래스 앞에 abstract를 붙여야 한다.
728x90

+ Recent posts