왜 자바인가?
JVM이 고도화된 좋은 기술이다.
JVM 덕에 매우 안정적인 언어라서 오랜 시간 많은 툴들이 Java 생태계 안에서 개발되었다.
자바 특징
1. 객체지향 프로그래밍
2. “Write Once, Run Anywhere”
3. 정적 타입 언어
한참 파이썬만 썼어서 정적 타입 언어에 다시 적응해야한다ㅜㅜ
자바의 실행 과정
컴파일 과정
.java -> (java compiler) -> .class (java bytecode)
런타임 과정 (with JIT 컴파일러)
.class -> (JVM) -> run!
입문 용어 정리
Java 기본 라이브러리 "Collection"
타입 시스템 유연성을 제공하는 "제네릭스"
"JVM JRE JDK"
JVM : 자바 가상 머신. JIT 컴파일러 방식. 빠른 코드 실행과 디바이스 호환성을 위해서 고안된 기술
JRE : 자바 런타임 환경. 자바를 돌리는데 필요한 패키지들. JVM이 여기에 포함됨
JDK : 자바 개발 키트. 개발자를 위한 개발툴+JRE 패키지
(JDK 패키징이 잘 되어있어서 환경설정과 설치가 굉장히 편했다.)
빌드 자동화 툴
인텔리제이로 프로젝트 생성 누르자마자 당황했던 부분. Gradle..? Maven..?
(찾아보니 빌드 자동화 툴이라고 한다. 빌드..를 파이썬 쓸때는 할 일이 없어서 잊고 있었다. 잘은 모르지만 C에서는 빌드툴이 통상적으로 하나 썼던것 같은데. 터미널에서 그냥 make 솰라솰라 해서 빌드했던 기억이 있다. 그때 다른 빌드툴에 대한 얘기를 들어보지 못했다. 그래서 빌드툴도 진보가 필요한 기술이라고는 생각 안해봤던것 같다. 아무튼. 캐싱이나 패키징 같은 부분에서 기술적인 차이가 있나보다. Gradle이 최신 기술이라고 한다. 빌드툴 자체가 JVM 기반 언어인 Groovy로 작성되어있다는 정보를 봤는데, 심지어 Gradle DSL 이라고 Groovy나 Kotlin 선택도 가능하다. 빌드 도구를 내 프로젝트에 맞게 커스텀할 수 있나보다.)
일단 Gradle만 사용해서 학습하겠다.
프로젝트 안에 gradle wrapper, gradlew, gradlew.bat 이런 파일들이 포함되어있다. 별도의 gradle 설치 없이도 실행이 가능한 뭐 그런거라고 한다. 프로젝트마다 빌더 버전 맞추기가 번거로우니 그것까지 프로젝트에 한꺼번에 패키징 하는 느낌인 것 같다.
신기하다. 다른 언어들보다 특히 많은 기술이 집약되어있는 것 같다. 많이 쓰는데는 다 이유가 있다.
package, class, ClassPass
package : 프로젝트 내 위계, dot(.)으로 구분, 기능/기술적인 부분을 분리
class : 코드 작성은 모두 클래스 블럭 안에. 파일 이름과 클래스 이름이 같아야함. class 별로 독립된 .class 파일이 생성.
class 이름 : 클래스로더가 클래스를 로드 할 때 위계까지 포함해서 인식하므로 위계가 같이 않으면 class 이름이 같아도 실행됨.
클래스패스 (Classpath) : JAVA_HOME/lib 디렉토리, java 명령어를 수행하는 현재 디렉토리가 클래스패스에 자동으로 포함됨
클래스패스는 환경변수로 지정 ($CLASSPATH), java 파라미터 (-cp, -classpath) 로 실행시 전달 가능
라이브러리를 여러개 사용 시 CLASSPATH 안에 : 로 구분해서 경로를 넣어줘야함
ex)
javac -cp ../ex1:. filename.java
java -cp ../ex1:. filename
빌드, 실행 둘다 클래스패스를 작성해줘야함
변수와 상수
변수 : [접근제어자] [자료형] [이름] = [값]
CamelCase (de facto standard): 변수 이름 붙이는 규칙. 첫글자 소문자 그 뒤는 띄어쓰기마다 대문자
(낙타 굽은 등이랑 비슷해서..)
상수 : final [자료형] [이름]
기본 자료형 Primitive Type
수 자료형
byte : 1바이트 정수 (-128~127) 혹은 char 아스키코드
short : 2바이트 정수 (2^15 약 +-32000)
int : 4바이트 정수 (2^31 약 20억)
long : 8바이트 정수 L (2^63 약 19자리)
float : 4바이트 실수 F (유효자릿수 7)
double : 8바이트 실수 d (유효자릿수 16) (소수점 작성시 디폴트 자료형)
BigDecimal
자료형 클래스에서 최대 최소값 확인 가능
sout(Short.MAX_VALUE), MIN_VALUE
Integer.MAX_VALUE
Long.MAX_VALUE
Float
Double
글자 자료형
char
bool
boolean : true, false;
참조 자료형 Reference Type
문자열
String str = “hello world!”;
배열
자료형[] 변수 = new 자료형[배열크기] (선언시 크기고정)
int[] intArray = new int[]{1,2,3,4,5};
sout(Arrays.toString(intArray));
다차원 배열 출력 : Array.deepToString(arr)
변동 크기 배열은 ArrayList 라는 Collection 사용
연산자
산술연산자
나누기 연산 : 정수/정수 = 정수 (몫)
/0 : ArithmeticException (/ by zero) (runtime exc)
대입연산자
+= 같은것들 쓸 수 있음
비교연산자
>, >=, ==, !=
논리연산자
&& (and)
|| (or)
^ (xor) (tf 일때만 t)
! (not)
비트연산자 (bitwise operators)
조건문
if
if(조건){} else if(조건){} else{}
switch
switch (입력변수) {
case 입력값1 : 실행구문
break;
default : 기본실행구문 (else)
break;
} //break에서 느껴지는 세월의 향기
enum class
삼항연산자 (Ternary Operator)
(조건식) ? T : F
//ex)
String result = (a<10)? "10보다 작다" : (a==10)? "10이다" : "10보다 크다";
반복문
for
for (초기값; 조건식; 증강식){} //(조건 true 일때 실행)
for - each
for (받는 변수 : 주는 변수(이터러블 객체)) {}
while
while(조건)
do-while
do {} while(); //실행문 우선, 그다음 조건 확인
continue; break;
++i, i++ 연산자 제공
객체지향프로그래밍 (Object-Oriented Programming) - 클래스,인스턴스,메소드
클래스와 인스턴스
클래스(Class) : 붕어빵틀 (개념)
인스턴스(Instance) : 찍어낸 붕어빵 (실체)
메소드
메소드(method) : 클래스 안에 선언된 함수 (멤버함수)
이름 짓기 : 동작을 잘 표현하도록 (good readability)
de facto-standard : 동사로 시작, camel case
선언 : 접근제어자 반환타입 메소드이름 (타입 변수명, …) {}
접근 제어자 default : package-protected 에 대해
https://hyeon9mak.github.io/Java-dont-use-package-private/
접근제어는 최대한 좁게 하는게 좋다는걸 어디서 봤던것 같아서 나도 글쓴이와 같은 생각을 했을 것 같다. 무엇보다 패키지 구조가 바뀔 가능성 떄문에 사용하지 않는다는게 눈에 띄었다. (합리적)
정적 메소드 (static method)
인스턴스 없이도 사용할 수 있는 함수
선언 : 접근제어자 static 반환타입 메소드이름() {}
클래스.메소드(파라미터) 로 사용
정적 메소드는 객체 상태에 독립적이어야한다. 파라미터로 받은 값, 다른 정적 리소스 +메소드 내부 작동만으로 구현되어야함.
인스턴스 메소드 (instance method)
생성자
인스턴스 생성시 초기화 메서드. new 새로 생성될때 자동 호출.
조건 : 생성자명 = 메서드명, return 없음
기본 생성자
상속
UML (Unified Modeling Language) Class Diagram
코드를 재사용하는 방식 중 하나, 코드 관리에 용이
특징
부모클래스로부터 정의된 필드와 메소드를 물려받는다.
새로운 필드와 메소드 추가 가능
물려받은 소스 수정 가능
상속 선언 :
접근제어자 class 이름 extends 부모클래스 {}
자식 클래스는 부모 변수에 할당할 수 있다.
부모클래스 변수에 할당한 경우 자식 클래스에 추가한 내용은 접근할 수 없다.
상속은 하나에서만 받을 수 있다. (다중상속 허용 x)
슈퍼 메소드
부모 클래스를 의미
자식은 부모의 생성자를 포함하는 생성자를 가지고 있어야한다.
Dog(String name) {
super(name);
}
오버로딩 (overloading)
한 클래스 내에서 동일한 이름의 메소드를 여러개 정하는 것
조건 : 메소드 이름이 동일, 매개변수 개수 혹은 타입이 달라야함. (리턴 타입만 다른건 불가능)
오버라이딩 (overriding)
부모 클래스로부터 상속받은 메소드를 재정의
조건 : 부모 클래스 메서드와 이름, 매개변수, 반환타입이 같아야함
오버라이드한 메서드 위에는 @Override 를 명시해주는게 원칙
접근제어자 (access modifier)
외부에서의 접근을 제한
종류
- private : 같은 클래스 내에서만
- default : 같은 패키지 내에서만
- protected : 같은 패키지 내에서, 다른 패키지 자손 클래스
- public : 접근 제한 없음
+ 하나의 클래스 안에서 private 메서드를 호출하는 public 메서드가 있다면 해당 퍼블릭 메서드를 통해서 private 메서드를 외부에서도 호출할 수 있음
outer 클래스 : public / default
inner 클래스 : public / default / private
(…이때까지 봤던 것 중에 제일 헷갈린다)
추상클래스 (abstract class)
추상메소드를 선언할 수 있는 클래스
상속받는 클래스 없이 그 자체로 인스턴스를 생성할 수 없음. 추상클래스를 상속받는 클래스를 통해서 생성해야함. 타입으로 지정할수는 있음
접근제어자 abstract class 클래스명 {}
추상메소드
메소드 시그니처만 설계된 상태에서 수행 코드는 없는 껍데기 (상속받는 클래스마다 매번 동작이 달라지지만 꼭 작성해야하는 경우)
abstract void 메소드 ();
인터페이스 (Interface)
자바의 인터페이스 : 객체의 특정 행동만 정의하고 실제 구현은 implements 한 클래스에 맡기는 문법 (구현체가 필요한 경우 default 키워드로 작성 가능)
메소드 껍데기만 정의 (추상메소드처럼)
implements 로 인터페이스를 꽂은 클래스에서 인터페이스에 선언된 모든 메서드를 구현해야함.
static 메소드 만들 수 있음.
(인터페이스 특성상) 디폴트 접근제어자 = public
인터페이스 vs 추상클래스
주된 할 일에 따라 선택하면 되는 듯 하다.
범용. 추상메소드가 메인 -> 인터페이스
클래스로서의 역할이 메인 + 일부 자유도 오픈 -> 추상클래스
좋은 코드 : 인터페이스 명세가 매우 잘 되어있고 상속을 최소화함
(상속이 깊어지면 읽고 이해하기 힘들어져서 그런듯. 각 기능의 핵심 요약, 철저한 분류 기준을 통해서 인터페이스를 잘 설정하는게 중요한듯)
(객체 지향을 잘 적용해볼 수 있는게 소울류 게임 아닐까? 몬스터 종류가 엄청 다양한데, 깊이(난이도)/넓이(챕터컨셉) 각각 방향으로 계층화가 되어있음)
(다시 한 번 느끼지만 역시 코드도 글이다. 백과사전 같은. 간결,핵심,가독성. 개발자에게 특히 글쓰라는 조언이 많은 이유는 사실상 읽고 쓰는 직업이기 때문인건가)
예외, 에러 처리 (Exception, Error Handling)
비정상 종료를 막기, 코드 보완 가이드 (with method signechar)
자바 예외 클래스 위계구조 (hieararchy)
자바는 상속을 이용해서 모든 예외를 표현
사용자 정의 예외 처리는 error나 exception을 상속받아 만들면 됨.
error : 강종 필요
exception : 강종되지 않게 처리할때
try-catch-finally
try { }
catch (FileNotFoundException e) {}
catch (IOException e) {}
catch (Throwable e) {}
finally {예외 발생여부 관계 없이 항상 수행}
exception hierarchy 최상단에 Throwable 이 있기 때문에 Throwable로 잡으면 자바의 모든 예외를 잡을 수 있음.
catch 블럭에서 한번 잡히면 뒤로 전파되지 않음. 또 전파하고 싶으면 catch 블럭 마지막에 throw 로 또 던져줄수는 있음.
try-with-resource
try (요기) {}
try 구문 안에서만 사용되는 자원을 try-catch 구문이 끝나면 자동으로 닫을 수 있도록 하는 문법
보통 IO와 함께 쓰이는 문법. (파이썬 with 구문으로 open 하는 느낌)
AutoCloseable Detail
public abstract class OutputStream implements Closeable, Flushable{}
public interface Closeable extends AutoCloseable{}
public interface AutoCloseable{}
/* The close() method of an AutoCloseable object is called
automatically when exiting a try-with-resources block */
try 구문에는 AutoClosable 인터페이스를 꽂은 객체만 넣을 수 있음
메소드에서의 예외 선언
void methodThrowsException() throws Exception {}
void caller() {
try{
methodThrowsException();
} catch (Exception e) {}
}
throws : 이 메소드를 부른 상위에서 해당 에러를 처리할 것.
caller() 에서 methodThrowsException() 을 호출할 때 반드시 try-catch로 에러처리를 해줘야함. (그렇지 않으면 컴파일 에러)
RuntimeException의 경우 (물론) try-catch를 안해줘도 컴파일이 된다.
날짜와 시간
Date 클래스
unix epoch time : 1970년 1월 1일 00시 (UTC/GMT 자정기준) (한국시간 기준 9AM) (초, 밀리초, 나노초 단위로 카운트)
Date 클래스의 단점 : thread safe 하지 않다, API가 이해하기 어려움, Timezone 적용이 어려움. (the epoch time)
LocalDate, LocalTime, LocalDateTime
LocalDate : 연월일 만 다룸
LocalTime : 날짜 없이 시간만 다룸
LocalDateTime : 날짜, 시간 모두 표현
ZonedDateTime : timezone을 적용한 날짜와 시간
(이런것까지 만들어져있다고..? 싶을 정도로 안되는게 잘 없어보인다)
기간 (Period, Duration)
Period : 날짜 사이 기간
Duration : 시간 사이의 비교나 계산
콜렉션 Collection
자료구조 클래스 집합
List : ArrayList, LinkedList, Stack … : 순서있음, 중복허용
Set : HashSet, TreeSet … : 순서유지안됨, 중복불허
Map : HashMap, TreeMap … : 키값쌍, 순서유지안됨, 키중복불허
Stack : Stack, ArrayDeque … : LIFO
Queue : Queue, ArrayDeque … : FIFO
Stack : 인터페이스 말고 클래스로 존재. extends Vector (which implements List)
- peek (맨 위 열람), search (인덱스를 반환)
Queue : 은행 창구 줄서기, 인쇄작업 대기목록
- 우선순위 큐, 원형 큐, 원형 우선순위 큐 …
- poll, offer
ArrayDeque : 스택, 큐 범용 + 성능도 더 좋음 (Front, Rear)
- addFirst, addLast
- removeFirst, PollFirst
- getFirst, peekFirst
제네릭스 Generics
타입시스템을 유연하게 사용하는 기능
클래스나 메소드 레벨에서 명세(동작)는 같지만 타입만 다른 경우 객체를 생성할 때 타입을 지정할 수 있도록 하는 기능
제네릭스 형식, 약어
public class 클래스명<T> {}
public interface 인터페이스명<T> {}
<T> T[] 메소드이름 () {}
<T> or <E> == type, element
<K> == key
<V> == value
<N> == number
<R> == result
람다 Lambda
클래스와 함수를 선언하지 않고 함수형 표현을 하는 문법
람다식 (Lambda expression)
식별자 없이 실행 가능한 함수
함수 이름을 따로 정의하지 않고 바로 함수처럼 사용하는 문법. 익명함수.
// <기존 메소드>
int method1(int x) {}
// <람다식>
(int x) -> {} // 반환 타입은 실행블록 내 return 문을 참조하여 자동 판단
이중 콜론 연산자 ::
람다식을 더 줄인 문법. 호출하고자 하는 함수의 파라미터와 람다식을 통해 전달할 인자가 일치하는 경우 파라미터값 입력을 생략하고 원하는 함수만 입력.
// 그냥 람다
public static void main(String[] args) {
List<String> cities = Arrays.asList("서울","대전","대구","부산","찍고");
cities.forEach(x -> System.out.println(x));
}
// 이중 콜론
public static void main(String[] args) {
List<String> cities = Arrays.asList("서울","대전","대구","부산","찍고");
cities.forEach(System.out::println);
}
람다식 단점
- 람다식 함수는 재사용이 불가능
- 로그확인이나 디버깅이 어려울 수 있음. (함수의 정확한 이름과 위치가 나타나지 않기 때문)
스트림 Stream
자바에서 함수형 프로그래밍(functional programming)을 가능하게 하는 도구
컬렉션에서 많이 사용.
- 컬렉션 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자
- 필터링, 데이터변경, 타입이나 자료구조 변환 등에 많이 쓰임
- 스트림은 데이터 소스를 변경하지 않음.
- 스트림을 통과한 데이터는 아예 새로운 객체 (새로운 데이터)
- 작업을 내부적으로 반복 처리
- 컬렉션의 요소를 끝까지 읽고 나면 닫혀서 재사용이 불가능. 한번만 흘러감.
스트림 구조
- 스트림 생성 : Stream<T> Collection.stream()
- 중간 연산 (형변환, 필터링, 정렬 등) : map(변환), sorted(정렬), skip/limit(스트림자르기)
- 최종 연산 : 스트림 요소를 소모해서 결과 반환. 스트림이 닫힘. (collect() 로 다른 컬렉션으로 바꾸거나 reduce로 쌓아서 연산하기 등등)
예제
public class Ex1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("서울","부산","속초","서울"));
System.out.println(list); // [서울, 부산, 속초, 서울]
List<String> result = list.stream().limit(2).collect(Collectors.toList());
System.out.println(result); // [서울, 부산]
List<String> result2 = list.stream().filter("서울"::equals).collect(Collectors.toList());
System.out.println(result2); // [서울, 서울]
Set<String> result3 = list.stream().filter("서울"::equals).collect(Collectors.toSet());
System.out.println(result3); // [서울]
}
}
public class Ex3 {
static class Sale {
public Sale(String fruitName, int price, float discount) {
this.fruitName = fruitName;
this.price = price;
this.discount = discount;
}
String fruitName;
int price;
float discount;
}
public static void main(String[] args) {
List<Sale> saleList = Arrays.asList(
new Sale("Apple", 5000,0.05f),
new Sale("Grape", 3000, 0.1f),
new Sale("Orange", 4000, 0.2f),
new Sale("Pear", 1400,0f)
);
Stream<Sale> saleStream = saleList.stream();
saleStream.map(sale -> Pair.of(sale.fruitName, sale.price * (1-sale.discount) ))
.forEach(pair -> System.out.println(pair.getLeft() + "의 실 구매가: " + pair.getRight()));
}
}
(아오 복잡해~!!! 파이썬이 되게 발랑 까져있는 느낌… 장기가 다 보여..)
네트워킹
두대 이상의 컴퓨터를 케이블 또는 무선 통신으로 연결하여 네트워크를 구성하는 것
클라이언트/서버
IP 주소
인터넷 상에서 컴퓨터를 구별하는데 사용되는 고유값. 인터넷에 연결된 모든 컴퓨터 주소는 IP 주소를 갖는다. (집주소)
ifconfig
URL : Uniform Resource Locator
인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소
URL 형식
프로토콜(http)://호스트명:포트번호/경로명/파일명?쿼리스트링#참조
포트번호
컴퓨터에서 어떤 프로세스가 통신에 사용할 통로 (방주소)
기본값 http=80, https=443
API : Application Programming Interface
요청과 응답 형식 약속
Retrofit 라이브러리
TCP 소켓 프로그래밍
TCP와 UDP
TCP/IP 프로토콜
시스템간 통신 표준 프로토콜. 프로토콜의 집합.
TCP, UDP 가 TCP/IP 프로토콜에 포함. OSI 7계층 중 전송계층
TCP
전화와 유사.
데이터를 전송하기 전에 서버와 연결을 함. 그 뒤에 데이터 전송. 쌍방향.
UDP
우편과 유사.
연결하지 않고 데이터를 전송. 수신 확인을 하지 않아서 신뢰성이 형성되지 않음.
생활코딩 네트워크 : http://opentutorials.org/course/1688/9483
Java InputStream, OutputStream
바이트 단위 스트림. 최상위 추상 클래스.
Socket : 클라이언트와 서버가 TCP 연결이 성립된 후 만들어지는 연결 통로. InputStream과 OutputStream을 가지고 있으며 두 스트림을 통해서 서버와 클라이언트 사이에 데이터를 읽고 쓸 수 있음.
ServerSocket : 서버쪽 소켓. 연결 요청이 들어오게 되면 소켓을 생성하여 소켓간 통신이 이루어지는 역할을 수행.
'Languages > Java' 카테고리의 다른 글
JMX로 JVM 모니터링하기 입문 (0) | 2024.01.15 |
---|