//////
Search
🍇

[0928] 클래스 변수와 클래스 메소드 ,예외 처리, 선택정렬

생성일
태그
TodayILearn
java
생성일 1

예외 처리

문법 오류가 아닌 실행 중간에 발생하는 정상적이지 않은 상황을 처리하는 방법

Try & Catch

public static void main(String arg[]) { Scanner kb = new Scanner(System.in); try{ System.out.print("a/b...a? "); int n1 = kb.nextInt(); System.out.print("a/b...b? "); int n2 = kb.nextInt(); System.out.printf("%d / %d = %d \n", n1, n2, n1 / n2); // 예외 발생 } catch(ArithmeticException e) { System.out.println(e.getMessage()); } finally{ System.out.println("무조건 실행"); } System.out.println("Good bye~~!"); }
Java
복사
위의 코드에서 printf() 메소드를 사용할 때에 %d 로 설정해놓은 빈칸을 채우는 과정에서 타입이 맞지 않다면 오류가 발생 가능하다.
때문에, 발생 가능한 오류가 있을 때에는 미리 try로 그 부분을 감싸 이에 대처할 수 있게 해야한다.
예상된 오류가 발생시, catch로 감싼 코드가 실행되며 소괄호에는 대처할 오류의 종류를 기입한다.
finally 로 감싼 부분은 문자열로 기입되었듯 무조건 실행되는 부분이며, 위 과정으로 예외 처리가 가능하다.

throws

메서드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할
try~catch 블록 대신 사용 가능
예제 코드 설명
BufferedReader를 사용하여 readLine() 메서드를 호출할 때 항상 예외처리를 해줘야 함
readLine()을 할 때마다 try~catch 블럭을 사용하거나 throws 키워드를 사용하면 됨
import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; class ThrowsTest { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String input = br.readLine(); } }
Java
복사

throw? throws?

throw와 throws는 모두 예외처리를 위한 문법이지만, 역할은 명백히 다름
throw
예외를 강제로 발생시키는 것
다른 언어에도 존재함
ex) param에 데이터를 담아 GET 메서드로 페이지를 가져오려하는 경우, 만약 param의 값이 잘못돼있으면 throw new BadRequestException();으로
throws
메서드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 것

클래스변수

클래스 변수란?

클래스 내에 Static 키워드로 선언된 변수
처음 JVM이 실행되어 클래스가 메모리에 올라갈 때 ~ 프로그램이 종료될 때까지 유지
클래스가 여러 번 생성되어도 Static 변수는 처음 딱 한 번만 생성됨
한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야 할 경우 클래스변수로 선언
모든 인스턴스가 공통된 저장공간을 공유

클래스 변수 사용 이유

자바는 캡슐화 원칙에 따라 어떤 변수나 함수도 클래스 바깥에 존재할 수 없기 때문이다.

클래스변수 접근방법

접근 영역(클래스 내부, 외부) 을 기준으로 크게 두가지로 나뉨
클래스 내부접근
클래스 외부접근

클래스변수 제약조건

static메소드는 오직 static멤버만 접근 가능
→ static메소드와 static멤버의 로드되는 시점은 동일하기 때문에 객체가 생성되지 않은 상황에서도 변수를 사용할 수 있어야 한다.
this 키워드 사용 불가
→ this는 실행 중인 객체를 가리키는 것이지만 static메소드는 객체가 생성되지 않은 상황에서도 호출이 가능하다.

Q. 클래스(static) 메소드에 인스턴스변수가 올 수 없는 이유는 무엇일까?

static 메소드가 호출이 될 때, 클래스의 객체를 생성하지 않았을 수도 있기 때문이다.
따라서 static 메소드는 인스턴스 변수를 사용하지 않고, 인스턴스 변수와 관련 없는 작업을 한다.
static 메소드는 객체 생성의 과정 없이 사용 가능하다.
인스턴스 변수는 객체 생성으로 메모리에 올라온 후에 사용할 수 있다.
따라서 생성 전에는 메모리에 존재하지 않기 때문에 사용이 불가능 하다.
정리하면, static이란 객체 생성 없이 한번 먼저 메모리에 올려서 , 공유하는 변수이다.
static을 자세히 이해하기 위해선 메모리의 이해가 필요하다.
다음 그림에서 Card 클래스의 객체가 생성되기 이전에 클래스 변수(static)에 접근하여 초기화하는 모습을 볼 수 있다.

Q. System.out.println 중 out과 println의 정체는?

System
System은 java.lang 패키지에 묶여 있는 클래스 이름이다.
그러나 컴파일러가 import 문을 삽입해 주므로 java.lang을 생략할 수 있다.
import java.util.lang.*;
out
out은 클래스 System의 이름을 통해 접근하므로,
System 클래스의 클래스 변수 이름임을 유추할 수 있다.
println()
println은 out이 참조하는 인스턴스의 메소드이다.

Q. main 메소드가 public이고 static인 이유는?

public static void main(String[ ] args) { … }
static
인스턴스 생성과 관계 없이 제일 먼저 호출되는 메소드이다.
public
main 메소드의 호출 명령은 외부로부터 시작되는 명령이기 때문에, 외부에서 접근이 가능한 public을 사용한다.

선택정렬 (Selection Sort)

주찬민
오름차순 기준으로 정렬한다.

사례 설명

운동장에 학생들이 모여있다고 생각하자. 학생들을 키 순서에 맞춰 일렬로 세우려면 어떻게 해야할까. 다음의 방법을 생각해보자.
1.
학생 열 명이 운동장에 모여있다. 선생님이 학생들을 줄 세운다.
2.
선생님은 학생들 중 키가 가장 작은 사람을 찾는다. 키가 가장 작은 학생으로 ‘선택’된 민준이를 맨 앞에 세운다.
3.
선생님은 다음으로 키가 작은 성진이를 선택한다. 선택된 성진이를 민준이 뒤에 세운다.
4.
남아 있는 학생 중 키가 가장 작은 학생을 한 명씩 뽑아 줄 세우는 과정을 반복하면 모든 학생이 키 순서에 맞춰 줄을 설 수 있다.
이 사례는 선택정렬 알고리즘의 예시를 보여준다. 다만, 실제 알고리즘 코드와 다른 점은 학생들의 자리를 바꿔가며 줄을 세운다는 것이다. (모두의 알고리즘 with 파이썬)

선택정렬 알고리즘 개념

선택정렬 알고리즘은 해당 순서에 원소를 넣을 위치는 이미 정해져 있고, 어떤 원소를 넣을지 선택하는 알고리즘이다.

정렬 과정

1.
주어진 배열 중에 최소값을 찾는다.
2.
그 값을 맨 앞에 위치한 값과 교체한다. (pass)
3.
맨 처음 위치를 제외한 나머지 배열을 같은 방법으로 교체 및 정렬한다.

정렬 GIF

Java Code

void selectionSort(int[] arr) { int indexMin, temp; for (int i = 0; i < arr.length-1; i++) { // 1. indexMin = i; for (int j = i + 1; j < arr.length; j++) { // 2. if (arr[j] < arr[indexMin]) { // 3. indexMin = j; } } // 4. swap(arr[indexMin], arr[i]) temp = arr[indexMin]; arr[indexMin] = arr[i]; arr[i] = temp; } System.out.println(Arrays.toString(arr)); }
Java
복사
1.
반복문의 i로 위치를 선택한다.
2.
반복문의 j로 i + 1번째 원소부터 순회하며 선택한 위치(indexMin) 값과 비교한다.
3.
현재 선택한 위치의 값보다 순회하던 값이 작다면, 위치(indexMin)를 순회하던 값의 위치(j)로 갱신한다.
4.
‘2번’ 반복문이 끝나면 indexMin에는 i번 위치에 들어가야할 값의 위치를 갖고 있으므로 서로 교환(swap)한다.

선택정렬 알고리즘의 특징

장점
자료 이동 횟수가 미리 결정된다.
알고리즘이 단순하다.
정렬을 위한 비교 횟수는 많지만, 실제로 교환하는 횟수가 적기 때문에 많은 교환이 일어나야 하는 자료상태에서 비교적 효율적이다.
정렬하고자 하는 배열 안에서 교환하는 방식이므로, 다른 메모리 공간을 필요로 하지 않는다. 제자리 정렬 (in-place sorting)
단점
안정성을 만족하지 않는다. 불안정 정렬 (unstable sort)

계산복잡도

시간복잡도

선택 정렬의 시간복잡도는 O(n2)O(n^2)이다.
데이터의 개수가 n개라고 가정하면,
첫 번째 반복에서 비교 대상 : 1 ~ (n - 1) ⇒ 비교 횟수 : n - 1
두 번째 반복에서 비교 대상 : 2 ~ (n - 1) ⇒ 비교 횟수 : n - 2
n - 1번째 반복에서 비교 대상 : (n - 1) ⇒ 비교 횟수 : 1
(n-1) + (n-2) + … + 2 + 1 = n(n-1)/2
비교하는 것이 상수 시간에 이루어진다는 가정 하에 n개의 배열을 정렬하는데 O(n^2)의 시간이 걸린다. 최선, 평균, 최악의 경우 모두 동일하다.

공간복잡도

선택 정렬의 공간복잡도는 O(n)O(n)이다.
주어진 배열 안에서 교환을 통해 정렬이 수행되므로 O(n)이다.

스택

마지막에 추가된 데이터가 가장 먼저 나오는 특징
LIFO( Last-in First-out )

스택 메소드 설명

PUSH
데이터 추가
POP
데이터 삭제(가장 마지막 데이터 삭제)
peek
스택의 최상위(마지막) 데이터 추출
isEmpty
스택이 비었는지 확인
clear
스택 데이터 삭제
class Stack { private int top; private int stackSize; private char stackArr[]; // 스택이 비어있는 상태인지 확인 // 스택 포인터가 -1인 경우 데이터가 없는 상태이므로 true 아닌 경우 false를 return public boolean isEmpty() { return (top == -1); } // 스택이 가득찬 상태인지 확인 // 스택 포인터가 스택의 마지막 인덱스와 동일한 경우 true 아닌 경우 false를 return public boolean isFull() { return (top == this.stackSize - 1); } // 스택에 데이터를 추가 public void push(char item) { if (isFull()) { System.out.println("Stack is full!"); } else { stackArr[++top] = item; // 다음 스택 포인터가 가리키는 인덱스에 데이터 추가 System.out.println("Inserted Item : " + item); } } // 스택의 최상위(마지막) 데이터 추출 후 삭제 public char pop() { if (isEmpty()) { System.out.println("Deleting fail! Stack is empty!"); return 0; } else { System.out.println("Deleted Item : " + stackArr[top]); return stackArr[top--]; } } // 스택의 최상위(마지막) 데이터 추출 public char peek() { if (isEmpty()) { System.out.println("Peeking fail! Stack is empty!"); return 0; } else { System.out.println("Peeked Item : " + stackArr[top]); return stackArr[top]; } } // 스택 초기화 public void clear() { if (isEmpty()) { System.out.println("Stack is already empty!"); } else { top = -1; // 스택 포인터 초기화 stackArr = new char[this.stackSize]; // 새로운 스택 배열 생성 System.out.println("Stack is clear!"); } } // 스택을 생성하는 생성자 public Stack(int stackSize) { top = -1; // 스택 포인터 초기화 this.stackSize = stackSize; // 스택 사이즈 설정 stackArr = new char[this.stackSize]; // 스택 배열 생성 } // 스택에 저장된 모든 데이터를 출력 public void printStack() { if (isEmpty()) { System.out.println("Stack is empty!"); } else { System.out.print("Stack elements : "); for (int i = 0; i <= top; i++) { System.out.print(stackArr[i] + " "); } System.out.println(); } } }
Java
복사