03 Feb 2022
|
TIL
학습과정
1. 알고리즘
silver 4. 보물(1026) 문제 풀이 방법을 추가했다.
- 처음 풀 때는 B에 있는 수를 재배열하지 말라는 조건을 충족시키지 못했다. 오늘 다시 풀어보면서 B의 최댓값을 구해주는 함수를 따로 생성해 조건을 충족시키면서 문제를 해결했다.
- 밀린 자바 공부를 진행하느라 오늘은 알고리즘 문제를 풀지 못했다. 아마 토요일까지는 문제를 풀 수 없을 것 같다. 일요일에 밀린 이번주 문제를 한 번에 풀어야겠다.
2. 자바
Chapter 13. 쓰레드와 Chapter 14. 람다와 스트림 중 람다 부분을 공부했다.
- Chapter 13. 쓰레드
- 멀티쓰레딩 장점과 단점
- start()와 run()
- 데몬 쓰레드
- 쓰레드 스케줄링 메서드: sleep(), join(), interrupt(), stop(), suspend(), resume(), yield()
- 쓰레드 상태: NEW, RUNNABLE, BLOCKED, WAITING, TERMINATED
- 쓰레드 동기화
- wait()와 notify()
- 기아 현상과 경쟁 상태
- volatile
- fork&join 프레임웍
- Chapter 14. 람다와 스트림_람다
- 람다식이란?
- 함수형 인터페이스
- java.util.function 패키지
- Function의 합성과 Predicate의 결합
- Function 합성: andThen(), compose(), identity()
- Predicate 결합: and(), or(), negate(), isEqual()
- 메서드 참조
3
내일은 오늘 끝내지 못한 스트림 부분과 남은 부분인 입출력과 네트워킹 부분을 공부해야겠다.
자바 기본서 1회독이 끝나가니 그 다음으로 공부할 자바의 심화된 내용을 다루는 책과 스프링 기본서를 찾아봐야겠다.
02 Feb 2022
|
TIL
학습과정
1. 알고리즘
silver 5. 수들의 합(1789) 문제를 풀었다.
- 문제를 처음 읽었을 때 이해하는데 시간이 조금 걸렸고, 아이디어를 생각해내는데도 시간이 걸렸다. (한 30분 정도..)
- 막상 아이디어를 떠올리고 나니 구현하는데는 오래 걸리지 않았다.
bronze 2. 5와 6의 차이(2864) 문제를 풀었다.
- 난이도가 높지 않아서 비교적 쉽고 빠르게 풀 수 있었다.
2
추석에도 계획한데로 공부를 진행하려고 했으나… 집중이 되지 않아 알고리즘 두 문제밖에 풀지 못했다..
진도가 밀린만큼 이번 주 분량을 모두 끝내기 위해 내일부터는 다시 집중해서 공부해야 겠다
- 목, 금: 자바의 정석 끝내기
- 토: 운영체제 남은 강의 모두 듣기
31 Jan 2022
|
알고리즘
프로그래밍
자바
bronze 2. 5 (2864)
출처 : https://www.acmicpc.net/problem/2864
문제
숫자 5를 볼 때, 5로 볼 때도 있지만, 6으로 잘못 볼 수도 있고, 6을 볼 때는, 6으로 볼 때도 있지만, 5로 잘못 볼 수도 있다.
두 수 A와 B가 주어졌을 때, 두 수의 가능한 합 중, 최솟값과 최댓값을 구해 출력하는 프로그램을 작성
입력: 두 정수 A와 B가 주어짐 (1 <= A, N <= 1,000,000)
출력: 두 수의 합 중 최솟값과 최댓값을 출력
풀이
- 아이디어: 최솟값을 구하는 함수와 최댓값을 구하는 함수 작성
- 최솟값을 구하는 함수: 주어진 수에 6이 들어있는 경우 6을 5로 바꿔준 후, 두 수의 합을 return
- 최댓값을 구하는 함수: 주어진 수에 5가 들어있는 경우 5를 6으로 바꿔준 후, 두 수의 합을 return
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int min = 0;
int max = 0;
StringTokenizer st = new StringTokenizer(sc.nextLine());
// 두 수 입력 받음
String num1 = new String(st.nextToken());
String num2 = new String(st.nextToken());
min = min(num1, num2); // 최솟값 구하기
max = max(num1, num2); // 최댓값 구하기
System.out.printf("%d %d%n", min, max);
}
// 두 수의 합 중에서 최솟값을 구하는 함수
public static int min(String num1, String num2){
int result = 0;
// 주어진 수들 중에서 6이 포함되어 있는 경우, 6을 5로 변경
if(num1.contains("6")){
num1 = num1.replace("6", "5");
}
if(num2.contains("6")){
num2 = num2.replace("6", "5");
}
// String형인 두 변수를 Int형으로 변경 후 더해줌
result = Integer.parseInt(num1) + Integer.parseInt(num2);
return result; // 최솟값 return
}
// 두 수의 합 중에서 최댓값을 구하는 함수
public static int max(String num1, String num2){
int result = 0;
// 주어진 수들 중에서 5가 포함되어 있는 경우, 5를 6으로 변경
if(num1.contains("5")){
num1 = num1.replace("5", "6");
}
if(num2.contains("5")){
num2 = num2.replace("5", "6");
}
// String형인 두 변수를 Int형으로 변경 후 더해줌
result = Integer.parseInt(num1) + Integer.parseInt(num2);
return result; // 최댓값 return
}
}
30 Jan 2022
|
알고리즘
프로그래밍
자바
silver 5. 수들의 합 (1789)
출처 : https://www.acmicpc.net/problem/1789
문제
서로 다른 N개의 자연수의 합이 S라고 함. S를 알 때, 자연수 N의 최댓값은 얼마일까?
입력: 자연수 S (1 <= S <= 4,297,967,295)
출력: S의 최댓값 출력
풀이
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int count = 0; // 더한 값의 개수를 저장
long add = 1; // sum에 더해나갈 값
long sum = 0; // 자연수들의 합을 저장
// long 변수 사용 이유: 입력 값의 범위가 int형이 담을 수 있는 범위를 넘어감
long num = sc.nextLong();
while (true){
sum += add ++; // sum에 add 값을 더한 후, add 값 1 증가
count ++; // count 값 1 증가
// sum의 값이 num의 값보다 커지면 count를 1 감소시키고 while 문을 벗어남
if (sum > num) {
count --;
break;
}
}
// count 값 출력
System.out.println(count);
}
}
28 Jan 2022
|
자바의 정석
JAVA
1. 지네릭스(Generics)
1.1 지네릭스란?
- 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크(compile-time type check)를 해주는 기능
- 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 버거로움이 줄어듦
- 타입 안정성을 높인다는 것은 의도하지 않은 타입의 객체가 저장되는 것을 막고, 저장된 객체를 꺼내올 때 원래의 타입과 다른 타입으로 잘못 형변환되어 발생할 수 있는 오류를 줄여준다는 의미
지네릭스의 장점
- 타입 안정성을 제공
- 타입체크와 형변환을 생략할 수 있어 코드가 간결해짐
- 다룰 객체의 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여줌
1.2 지네릭 클래스의 선언
클래스에 선언하는 지네릭 타입
class Box {
Object item;
void setItem(Object item) {this.item = item;}
Object getItem() {return item;}
}
- Box 클래스를 지네릭 클래스로 변경하면 클래스 옆에
<T>를 붙인 후, Object를 모두 T로 변경
class Box<T> {
T item;
void setItem(T item) {this.item = item;}
T getItem() {return item;}
}
지네릭스의 용어
Box<T>: 지네릭 클래스. ‘T의 Box’ 또는 ‘T Box’라고 읽음
T: 타입 변수 또는 타입 매개변수 (T는 타입 문자)
Box: 원시 타입(raw type)
지네릭스의 제한
- 지네릭 클래스 Box의 객체를 생성할 때, 객체별로 다른 타입을 저정하는 것은 적절하지만, 모든 객체에 대해 동일하게 동작해야하는 static 멤버에 타입 변수 T를 사용할 수 없음
- T는 인스터스변수로 간주되기 때문. static 멤버는 인스턴스변수 참조 불가
- static 멤버는 타입 변수에 지정된 타입, 즉 대입된 타입의 종류에 관계없이 동일한 것이어야 하기 때문
- 지네릭 타입의 배열을 생성하는 것은 허용되지 않음
- 지네릭 배열 타입의 참조변수를 선언하는 것은 가능하지만, 배열을 생성하는 것은 안됨
- new 연산자는 컴파일 시점에 타입 T가 뭔지 정확하게 알아야 하지만 컴파일하는 시점에서 T가 어떤 타입이 될지 전혀 알 수 없음
- 지네릭 배열을 생성해야할 필요가 있는 경우, new 연산자대신 ‘Reflection API’의
newInstance()와 같이 동적으로 객체를 생성하는 메서드로 배열을 생성하거나, Object 배열을 생성해 복사한 다음 T[]로 형변환하는 방법 등을 사용
1.3 지네릭 클래스의 객체 생성과 사용
Box<>의 객체에는 한 가지 종류 (T타입)의 객체만 저장 가능
class Box<T> {
ArrayList<T> list = new ArrayList<T>();
void add(T time) {list.add(item); }
T get(int i) {return list.get(i); }
ArrayList<T> getList() {return list; }
int size() {return list.size(); }
public String toString {return list.toString();}
-
참조변수와 생성자에 대입된 타입(매개변수화된 타입)이 일치해야 함. 일차하지 않으면 에러 발생
Box<Apple> appleBox = new Box<Apple>(); // OK
Box<Apple> appleBox = new Box<Graph>(); // 에러
-
두 타입이 상속 관계에 있더라도 에러 발생
// Apple이 Fruit의 자손이라 가정
Box<Fruit> appleBox = new Box<Apple>(); // 에러. 대입된 타입이 다름
-
두 지네릭 클래스의 타입이 상속관계에 있고, 대입된 타입이 같은 것은 괜찮음
// FruitBox가 Box의 자손이라고 가정
Box<Apple> appleBox = new FruitBox<Apple>(); // OK. 다형성
-
JDK1.7부터 추정이 가능한 경우 타입을 생략할 수 있게 됨
- 참조변수의 타입으로부터 어떤 타입의 객체만 저장하는지를 알 수 있기 때문에, 생성자에 반복해서 타입을 지정해주지 않아도 됨
-
extends를 사용하면, 특정 타입의 자손들만 대입할 수 있게 제한할 수 있음
1.5 와일드 카드
1.6 지네릭 메서드
// Collections.sort()
static <T> void sort(List<T> list, Comparator<? super T> c)
- 메서드의 선언부에 지네릭 타입이 선언된 메서드
- 지네릭 타입의 선언 위치는 반환 타입 바로 앞
- 지네릭 클래스에 정의된 타입 매개변수와 지네릭 메서드에 정의된 타입 매개변수는 전혀 별개의 것
- static 멤버에는 타입 매개변수를 사용할 수 없지만, 메서드에 지네릭 타입을 선언하고 사용하는 것은 가능
- 메서드에 선언된 지네릭 타입은 지역 변수를 선언한 것과 같다고 생각하면 됨
- 이 타입 매개변수는 메서드 내에서만 지역적으로 사용될 것이므로 메서드가 static이건 아니건 상관없음
- 지네릭 메서드를 호출할 때, 대입된 타입을 생략할 수 없는 경우에는 참조변수나 클래스 이름을 생략할 수 없음
1.7 지네릭 타입의 형변환
- 경고가 발생하지만, 지네릭 타입과 넌지네릭(non-generic)타입 간의 형변환은 항상 가능
- 대입된 타입이 다른 지네릭 타입 간에는 형변환이 불가능
- 와일드 카드가 사용된 지네릭 타입끼리도 형변환 가능하지만, 와일드 카드는 타입이 확정된 타입이 아니므로 컴파일러는 미확정 타입으로 형변환하는 것이라고 경고
1.8 지네릭 타입의 제거
- 컴파일러는 지네릭 타입을 이용해 소스파일을 체크하고, 필요한 곳에 형변환을 넣어준 후 지네릭 타입을 제거하므로 컴파일된 파일(*.class)에는 지네릭 타입에 대한 정보가 없음
지네릭 타입 제거 과정
- 지네릭 타입의 경계(bound)를 제거
- 지네릭 타입이
<T extends Fruit>라면 T는 Fruit로 치환. <T>인 경우 T는 Object로 치환됨
- 치환된 후 클래스 옆의 선언은 제거됨
- 지네릭 타입을 제거한 후에 타입이 일치하ㅈ 않으면, 형변환을 추가함
- 와일드 카드가 포함되어 있는 경우에는 적절한 타입으로의 형변환이 추가됨
2. 열거형(enums)
2.1 열거형이란?
- 서로 관련된 상수를 편리하게 선언하기 위한 것으로 여러 상수를 정의할 때 사용하면 유용
- 열거형이 갖는 값뿐만 아니라 타입도 관리하기 때문에 논리적인 오류를 줄일 수 있음
- 타입에 안전한 열거형(typesafe enum)이기 때문에 실제 값이 같아도 타입이 다르면 컴파일 에러가 발생
- 상수의 값이 바뀌면, 해당 상수를 참조하는 모든 소스를 다시 컴파일해야 했지만, 열거형 상수를 사용하면 기존의 소스를 다시 컴파일하지 않아도 됨
2.2 열거형의 정의와 사용
enum 열거형이름 { 상수면1, 상수명2, ... }
- {} 안에 상수의 이름을 나열해 정의
- 열거형에 정의된 상수를 사용하는 방법:
열거형이름.상수명
- 열거형 상수간의 비교에는 ‘==’ 사용이 가능. >, <와 같은 비교 연산자는 사용할 수 없고
compareTo()는 사용 가능
compareTo()는 두 비교대상이 같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수를 반환
- switch문의 조건식에도 열거형 사용 가능
- case문에는 열거형의 이름은 적지 않고 상수의 이름만 적어야 한다는 제약이 있음
모든 열거형의 조상 - java.lang.Enum
- Enum 클래스에 정의된 메서드
values(): 열거형의 모든 상수를 배열에 담아 반환. 모든 열거형이 가지고 있는 것으로 컴파일러가 자동으로 추가해줌
ordinal(): 모든 열거형의 조상인 java.lang.Enum 클래스에 정의된 것으로, 열거형 상수가 정의된 순서(0부터 시작)를 정수로 반환
2.3 열거형에 멤버 추가하기
-
ordinal()이 열거형 상수가 정의된 순서를 반환하지만, 이 값을 열거형 상수 값으로 사용하는 것은 좋지 않음
- 이유: 이 값은 내부적인 용도로만 상용되기 위한 것이기 때문
-
열거형 상수의 값이 불연속적인 경우에는 열거형 상수의 이름 옆에 원하는 값을 괄호()와 함께 적어주면 됨
```java
enum Diraction {EAST(1), SOUTH(5), WEST(-1), NORTH(10)}
-
지정된 값을 저장할 수 있는 인스턴스 변수와 생성자를 새로 추가해 주어야 함
- 먼저 열거형 상수를 모두 정의한 다음 다른 멤버들을 추가해야 함. 열거형 상수의 마지막에 ‘;’도 붙여야 함
2.4 열거형의 이해
- 열거형 상수 하나하나가 객체
- 모든 열거형은 추상 클래스 Enum의 자손
- 추상 메서드를 새로 추가하면, 클래스 앞에도
abstract를 붙여줘야 하고, 각 static 상수들도 추상 메서드를 구현해주어야 함
3. 애너테이션(annotation)
3.1 애너테이션이란?
- 소스코드의 주석(
/** ~ */)에 소스코드에 대한 정보를 저장하고, 소스코드의 주석으로부터 HTML 문서를 생성해내는 프로그램(javadoc.exe)을 만들어 사용함
/**로 시작하는 주석 안에 소스코드에 대한 설명들이 있고, 그 안에 @이 붙은 태그들이 있음
- 미리 정의된 태그들을 이용해 주석 안에 정보를 저장하고, javadoc.exe라는 프로그램이 이 정보를 읽어 문서를 작성하는데 사용
- 애너테이션: 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
- 애너테이션은 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있음
- JDK에서 제공하는 표준 애너테이션은 주로 컴파일러를 위한 것으로 컴파일러에게 유요안 정보를 제공
- 새로운 애너테이션을 정의할 때 사용하는 메타 애너테이션을 제공
- JDK에서 제공하는 애너테이션
3.2 표준 애너테이션
@Override
- 메서드 앞에만 붙일 수 있는 애너테이션
- 조상의 메서드를 오버라이딩하는 것이라는걸 컴파일러에게 알려주는 역할을 함
- 컴파일러가 같은 이름의 메서드가 조상에 있는지 확인하고 없으면, 에러메시지를 출력
@Deprecated
- 더 이상 사용되지 않는 필드나 메서드에 붙이는 애너테이션
- 이 애너테이션이 붙은 대상은 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미
@FunctionalInterface
- 함수형 인터페이스를 선언할 때, 이 애너테이션을 붙이면 컴파일러가 ‘함수형 인터페이스’를 올바르게 선언했는지 확인하고, 잘못된 경우 에러를 발생시킴
- 필수는 아니지만,붙이면 실수를 방지할 수 ㅜ있으므로 함수형 인터페이스를 선언할 때 애너테이션을 붙이는 것이 좋음
@SuppressWarnings
- 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해줌
- 애너테이션이 억제할 수 있는 경고 메시지 종류
- deprecation:
@Deprecated가 붙은 대상을 사용해서 발생하는 경고
- unchecked: 지네릭스로 타입을 지정하지 않았을 때 발생하는 경고
- rawtypes: 지네릭스를 사용하지 않아 발생하는 경고
- varargs: 가변인자의 타입이 지네릭 타입일 때 발생하는 경고
@SafeVarargs
- 메서드에 선언된 가변인자의 타입이 non-reifiable 타입일 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 unchecked 경고가 발생
- 컴파일 후에도 제거되지 않는 지네릭 타입을 reifiable 타입이라 하고, 제거되는 타입을 non-reifiable 타입이라 함
- 해당 코드에 문제가 없다면 이 경고를 억제하기 위해 애너테이션을 사용
- 이 애너테이션은 static이나 final이 붙은 메서드와 생성자에만 붙일 수 있음
3.3 메타 애너테이션
3.4 애너테이션 타입 정의하기
@interface 애너테이션이름 {
타입 요소이름(); // 애너테이션의 요소를 선언
...
}
애너테이션의 요소
- 애너테이션 내에 선언된 메서드를 의미
- 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지며, 상속을 통해 구현하지 않아도 됨
- 단, 애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해주어야 함. 요소의 이름도 같이 적어주므로 순서는 상관없음
- 애너테이션의 각 요소는 기본값을 가질 수 있으며, 기본값이 있는 요소는 애너테이션을 적용할 때 값을 지정하지 않으면 기본값이 사용됨
- 애너테이션 요소가 하나뿐이고 이름이 value인 경우, 애너테이션을 적용할 때 요소의 이름을 생략하고 값만 적어도 됨
- 요소의 타입이 배열인 경우, {}를 사영해서 여러 개의 값을 지정할 수 있음
마커 애너테이션 Marker Annotation
- 값을 지정할 필요가 없는 경우, 애너테이션의 요소를 하나도 정의하지 않을 수 있음
- Serializable이나 Cloneable 인터페이스처럼, 요소가 하나도 정의되지 않은 애너테이션을 마커 애너테이션이라 함
애너테이션 요소의 규칙
- 요소의 타입은 기본형, String, enum, 애너테이션, Class만 혀용됨
- ()안에 매개변수를 선언할 수 없음
- 예외를 선언할 수 없음
- 요소를 타입 매개변수로 정의할 수 없음
Chapter 12 끝!!!