스택 자료구조는 밑이 막힌 구조로, 맨 끝에 들어온 데이터가 맨 처음 나간다(후입선출, LIFO = Last In First Out).
예를 들어 12345의 순으로 값이 들어왔다고 하면, 나갈때는 54321순으로 나가야한다.
문자열 거꾸로 출력하기 등 에 이용할 수 있다.
다른 자료구조와는 조금 다르게 push를 이용해서 값을 넣는다.
public class StackApplication {
public static void main(String[] args) {
Stack<Coin> stack = new Stack<>();
// 수택에 값 넣기
stack.push(new Coin(100));
stack.push(new Coin(50));
stack.push(new Coin(20));
stack.push(new Coin(10));
System.out.println(stack);
// 스택에서 값 꺼내기
Coin coin = stack.pop();
System.out.println(coin.getValue());
Coin coin2 = stack.pop();
System.out.println(coin2.getValue());
System.out.println(stack);
}
}
이건 값을 빼내서 가지는 것이다. remove랑 헷갈릴 수 있는데 이건 빼서 없애는 것이 아니고 빼서 가지고 있다가 값을 가져오면 해당 값이 출력되게 하는 것이다.
public class StackApplication {
public static void main(String[] args) {
Stack<Coin> stack = new Stack<>();
// 수택에 값 넣기
stack.push(new Coin(100));
stack.push(new Coin(50));
stack.push(new Coin(20));
stack.push(new Coin(10));
System.out.println(stack);
// 스택에서 값 꺼내기
Coin coin = stack.pop();
System.out.println(coin.getValue());
Coin coin2 = stack.pop();
System.out.println(coin2.getValue());
System.out.println(stack);
}
}

꺼낸 값을 getValue를 통해 확인 할 수 있고, 값을 두번빼서 스택에는 100과 50만 남아있다.
stack의 자료구조에서 가장 위에 있는 값을 확인하는 방법이 있다.
public class StackApplication {
public static void main(String[] args) {
Stack<Coin> stack = new Stack<>();
// 수택에 값 넣기
stack.push(new Coin(100));
stack.push(new Coin(50));
stack.push(new Coin(20));
stack.push(new Coin(10));
System.out.println(stack);
// 스택에서 값 꺼내기
Coin coin = stack.pop();
System.out.println(coin.getValue());
Coin coin2 = stack.pop();
System.out.println(coin2.getValue());
//출력
System.out.println(stack);
// 가장 위에 있는 값 확인하기
System.out.println(stack.peek());
}
}
20까지 빠져서 50이 제일 위의 값이다.
스택과 다르게 맨 처음 들어간 자료가 맨 처음으로 나오는 자료구조로 선인선출이다(FIFO). 스택은 아래가 막혀있지만 큐는 아래가 뚫려있는 구조라고 보면된다.
queue는 stack와 다르게 인터페이스이다. 그래서 자식클래스를 호출해야한다. 자식 클래스에는 배열객체들이 있는데 다른것보다도 LinkedList가 성능이 좋아서 이것을 사용하는 것이 보편적이다.
스택은 push를 사용했지만, 큐에서는 offer를 사용해서 값을 집어 넣는다.
public class QueueApplication {
public static void main(String[] args) {
Queue<Message> messages = new LinkedList<>();
messages.offer(new Message("sendMail", "홍길동"));
messages.offer(new Message("sendSMS", "장길산"));
messages.offer(new Message("sendKakao", "홍두깨"));
messages.poll();
}
}
값들이 잘 들어갔다.
poll을 이용해 값을 꺼낸뒤 확인 할 수 있다. 이것도 pop과 비슷한 개념이다.
public class QueueApplication {
public static void main(String[] args) {
Queue<Message> messages = new LinkedList<>();
messages.offer(new Message("sendMail", "홍길동"));
messages.offer(new Message("sendSMS", "장길산"));
messages.offer(new Message("sendKakao", "홍두깨"));
System.out.println(messages);
System.out.println(messages.poll());
}
}

가장 먼저 들어간 홍길동이 나오는 것을 볼 수 있다.
가장 나중에 들어간 값을 확인 하는 것이다. stack과 같이 peek을 이용한다.
public class QueueApplication {
public static void main(String[] args) {
Queue<Message> messages = new LinkedList<>();
// 값 넣기
messages.offer(new Message("sendMail", "홍길동"));
messages.offer(new Message("sendSMS", "장길산"));
messages.offer(new Message("sendKakao", "홍두깨"));
// 출력
System.out.println(messages);
// 값 꺼내기
System.out.println(messages.poll());
System.out.println(messages.poll());
System.out.println(messages.peek());
}
}
가장 마지막에 들어간 홍두깨가 출력되는 것을 확인 할 수 있다.
유용한 함수들이 있는 클래스이다. 정렬(오름/내림), 특정값 채우기같은 함수들이 존재한다.
배열만 다룰 수 있다.
배열의 값들을 알고 싶을때 사용할 수 있다.
public class ArraysApplication {
public static void main(String[] args) {
int[] arr = {0,1,2,3,4};
int[][] arr2 = {{10, 11, 12}, {20,21,22}};
System.out.println(Arrays.toString(arr));
}
}

2차원 배열에서는 일반 toString이 아니라 deepToString을 사용해야한다.
public class ArraysApplication {
public static void main(String[] args) {
int[] arr = {0,1,2,3,4};
int[][] arr2 = {{10, 11, 12}, {20,21,22}};
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.deepToString(arr2));
}
}

int[] arr3 = new int[5];
Arrays.fill(arr3,9);
System.out.println(Arrays.toString(arr3));
하나의 값으로 채우고 싶을 때 for을 사용하지 않고 값을 채울 수 있다. fill(배열, 값)을 해주면 그 배열 전체를 값으로 꽉 채울 수 있다.
Character[] chArr = {'A','B','C','D'};
Arrays.sort(chArr, Collections.reverseOrder());
System.out.println(Arrays.toString(chArr));
sort(배열, 정렬기준)을 입력하면된다. reverseOrder이 내림차순을 의미한다.
참고로 reverseOrder을 사용할때는 객체 자료형을 사용해야한다. 기본 자료형을 사용하면 오류가 생긴다.

아스키코드값이 큰 알파벳부터 나오는 것을 확인 할 수 있다.
Character[] chArr = {'A','B','C','D'};
Arrays.sort(chArr);
System.out.println(Arrays.toString(chArr));

아스키코드값이 작은 알파벳부터 나오는 것을 확인 할 수 있다.
정렬에는 여러 종류가 있다. 이 중에서도 힙정렬과 퀵정렬이 속도가 빠르다. 위에선 퀵 정렬을 사용한 것이다.
하지만 퀵 정렬도 단점이 있는데, 값이 미리 정렬되어 있으면 굉장히 느리다. 예를 들어 배열이 1,2,3,4로 이미 오름차순으로 정렬이 되어있으면 느리게 동작한다.
1) 조건 : 먼저 오름차순으로 정렬을 해야 탐색이 가능하다.
2) 기능 : 특정값을 배열에서 몇 번째 인덱스에 존재하는 지를 확인 할 수 있다.
3)원리 : 1부터 숫자를 세면서 어디에 있는지를 찾는 것이 아니라 중간값을 찾아서 찾는 값이 중간값보다 큰지 작은지 비교해서 그 것을 기준으로 찾는다. 일반 반복문을 이용하는 것보다 더 빠르다.
Character[] chArr2 = {'A','B','C','D'};
Arrays.sort(chArr2);// 오름차순으로 먼저 정렬해준다.
int pos = Arrays.binarySearch(chArr2,'B');
System.out.println(pos);

1번 인덱스에 B가 존재한다는 것을 알 수 있다.
일반 배열을 만들고 사용하고 있는데 이것을 크기가 한정이 없는 List배열로 사용해야하는 상황이 생기면 사용 할 수 있을 것 같다.
Integer[] iArr = {1,2,3,4,5};
List<Integer> list = new ArrayList<>(Arrays.asList(iArr));
System.out.println(list);
객체를 생성할때 ArrayList의 ()안에 Arrays.asList(배열)을 해주면 된다.

List, Set, Map에 유용한 함수들이 있다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5,6);
System.out.println(list);
}
}

값을 한번에 여러개 넣을 수 있다.
배열에서 뒤의 값을 앞으로 보내버리는 함수가 있다. 회전시켜 앞으로 보낸다고 해서 rotate인거 같다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
System.out.println(list);
// list값들을 오른쪽으로 회전시키기
Collections.rotate(list, 2);
System.out.println(list);
}
Collections의 rotate함수를 사용하면 된고 rotate(배열, 오른쪽으로 이동시킬 크기)를 입력해주면된다.
특정 인덱스의 값을 서로 교환 할 수 있다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
System.out.println(list);
// list값들을 오른쪽으로 회전시키기
Collections.rotate(list, 2);
System.out.println(list);
// 값 서로 교환하기
Collections.swap(list, 0, 1);
System.out.println(list);
}
}
swap(배열, 교환할 값의 인덱스, 교환할 값의 인덱스)를 입력해주면 해당 인덱스의 값이 서로 바뀐다.
일반 배열에는 Arrays를 이용해서 정렬을 했다. List배열에서는 Collections를 이용해서 정렬이 가능하다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
System.out.println(list);
// list값들을 오른쪽으로 회전시키기
Collections.rotate(list, 2);
System.out.println(list);
// 값 서로 교환하기
Collections.swap(list, 0, 2);
System.out.println(list);
// 내림차순 정렬
Collections.sort(list, Collections.reverseOrder());
System.out.println(list);
}
}

Arrays가 아니라 Collections를 이용한다는 거 말고는 같다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
System.out.println(list);
// list값들을 오른쪽으로 회전시키기
Collections.rotate(list, 2);
System.out.println(list);
// 값 서로 교환하기
Collections.swap(list, 0, 2);
System.out.println(list);
// 내림차순 정렬
Collections.sort(list, Collections.reverseOrder());
System.out.println(list);
// 오름차순 정렬
Collections.sort(list);
System.out.println(list);
}
}

이것도 같다.
이 정렬 방법은 일반 배열의 정렬인 퀵정렬과는 다르게 팀정렬을 사용한다. 속도는 퀵정렬과 비슷하지만 팀정렬은 이미 정렬이 되어있어도 속도가 느려지지 않는다는 장점이 있다.
List에서도 특정값이 몇번 인덱스에 있는 지를 찾아주는 함수가 있다. 아니 일반배열의 함수와 같다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
// 오름차순 정렬
Collections.sort(list);
System.out.println(list);
// 이진 탐색
int index = Collections.binarySearch(list, 3);
System.out.println(index);
}
}

3이 배열에서 index 2에 있다는 것을 알려준다.
public class CollectionsApplication {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// list에 값 여러개 넣기
Collections.addAll(list, 1,2,3,4,5,6);
// 최댓값 찾기
System.out.println(Collections.max(list));
// 최솟값 찾기
System.out.println(Collections.min(list));
}
}

값을 나중에 지정해주려고 null을 사용하기도 하는데 예외가 발생할 수 있기 때문에 사용을 지양하는게 좋다.
public class NullApplication {
public static void main(String[] args) {
String data = null; // 값을 나중에 지정해주려고 보통 null을 사용하는데 예외때문에 사용을 지양하는게 좋다.
System.out.println(data.toString());
}
}

값이 널이면 함수를 실행할 수 없는데, 사용하다보니 다음과 같이 에러가 났고 밑줄친 에러를 보면 NullPointException인 것을 확인 할 수 있다.
배열의 크기보다 큰 index 번호에 접근했을 때 발생하는 예외이다. 예를 들어 크기가 5인 배열이 있는데 이 배열의 10번 값을 출력한다고 하면 이 예외가 발생한다.

main함수는 args를 매개변수로 받는 함수인데, 아직 아무 값도 들어가지 않았다. 그런데 우리가 값을 호출했으므로 위와 같은 에러가 발생하는 것이다.
문자열이나 특정 값을 숫자로 변경하는 상황이 있다. 예를들어 "123"을 Integer.parseInt("123")숫자로 바꿀수 있다. 그런데 "asdf"는 숫자로 바꿀수 없는데 이것을 숫자로 바꾸려할 때 다음과 같은 에러가 발생할 수 있다.
public class NumberFormatApplication {
public static void main(String[] args) {
String data1 = "100";
String data2 = "a100";
int a = Integer.parseInt(data1);
int b = Integer.parseInt(data2);
System.out.println(a);
System.out.println(b);
}
}

"a100"은 숫자로 변경할 수 없어서 다음과 같은 에러가 발생한다.
lassCastException은 자바에서 발생하는 런타임 예외 중 하나로, 잘못된 형변환을 시도할 때 발생한다. 이것은 주로 다음과 같은 상황에서 발생한다
객체를 부모 클래스 타입으로 선언하고 실제로는 자식 클래스의 객체를 가리키고 있는 경우, 부모 클래스 타입으로 캐스팅하려 할 때 발생한다. 이는 부모 클래스와 자식 클래스 간의 상속 관계가 없는 경우 발생할 수 있다.
class Parent {}
class Child extends Parent {}
public class Main {
public static void main(String[] args) {
Parent parent = new Parent();
// 아래의 캐스팅은 ClassCastException을 발생시킵니다.
Child child = (Child) parent;
}
}
객체를 인터페이스 타입으로 선언하고 실제로는 해당 인터페이스를 구현한 클래스의 객체를 가리키고 있는 경우, 해당 인터페이스 타입으로 캐스팅하려 할 때 발생할 수 있다. 이는 해당 클래스가 해당 인터페이스를 구현하지 않은 경우에 발생할 수 있다.
interface MyInterface {}
class MyClass implements MyInterface {}
public class Main {
public static void main(String[] args) {
MyInterface myInterface = new MyClass();
// 아래의 캐스팅은 ClassCastException을 발생시킵니다.
MyClass myClass = (MyClass) myInterface;
}
}
일반적으로 호환되지 않는 클래스 간의 형변환을 시도할 때 발생할 수 있다. 이는 컴파일러가 검사하지 않는 런타임 시점에 발생하는 오류다.
class FirstClass {}
class SecondClass {}
public class Main {
public static void main(String[] args) {
FirstClass firstObj = new FirstClass();
// 아래의 캐스팅은 ClassCastException을 발생시킵니다.
SecondClass secondObj = (SecondClass) firstObj;
}
}
이러한 상황에서는 형변환 전에 instanceof 연산자를 사용하여 형변환이 유효한지 먼저 확인하는 것이 좋다. 또한 클래스 간의 상속 관계나 인터페이스의 구현 여부를 정확히 이해하고, 형변환을 올바르게 수행해야 한다.
예외처리를 하지 않으면 예외가 발생 시 프로그램이 종료될 수 있다. 그래서 이것을 막고 사용자에게 특정 화면을 보이게 하면서 계속 프로그램이 실행 될 수 있도록 만들어야한다.

forName은 클래스의 정보를 알려주는 함수인데 String2라는 클래스는 없기 때문에 그림과 같이 에러가 발생한다.
이런화면을 사용자에게 보여 줄 수는 없으니 에러 처리를 해보자.
public class TryCatchFinallyApplication {
public static void main(String[] args) {
try {
Class aClass = Class.forName("String2"); // 에러 발생
}catch (ClassNotFoundException e) {
System.out.println("클래스가 존재하지 않음");
}
}
}

깔끔하게 결과가 나오는 것을 볼 수 있다.