(Day12) - 메서드와 스트림, 리팩터링
이 글은 제가 교육을 수강하며 기록하고 추가한 내용입니다. 강사님과 무관하게 잘못된 내용이 있을 수 있습니다.
클라우드 기반 웹 데브옵스 프로젝트 개발자 교육 과정 (5기)
- 비트캠프 엄진영 강사님 (https://github.com/eomjinyoung/)
- 훈련기관 : 네이버클라우드주식회사
- 기간: 2023-11-14 ~ 2024-5-22
- 남은 일자 : 117 일 ( 12/129 )
12일차(2023-11-29, 수)
강의내용
아침복습
- 증감연산자
- 전위, 후위 증감 연산자는 하나의 변수에 대해 한 문장에서 동시에 사용할 수 없다.
- 값이 반환되기 때문이다.
- 연산자 우선순위
- argument 내부 expression 다 처리된 이후 method가 처리된다.
- 대입연산자 사용법
- =, +=, -=, *=, /= 는 왜 쓰는가? 더 간결하게, 편하게 코드를 작성하기 위해서다.
- if, else
- if문은 블럭을 사용하는 것을 권장한다. (구글 스타일) else는 별도로 사용할 수 없다. 또한 가장 가까운 if에 소속된다. (들여쓰기에 속지 말라) else if 는 별도의 문법이 아니라, else 문 내부에 if가 소속된 것이다. 가독성이 좋아 자주 사용되나, else if 라는 별도의 문법이 있는 것이 아니다. 들여쓰기를 잘 맞춰야 다른 개발자들에게 의도를 잘 전달할 수 있다.
- switch, case
- 4byte 정수형을 case에 둘 수 있다. char 타입과 short 타입에 대해서 같은 이진수라고 하더라도 JVM이 다르게 해석한다. 0x75F4 라는 같은 값이 들어가 있다고 해도 short 에서는 -30196 으로, char에서는 0x8A0C
- case 작성법
- case에는 변수가 올 수 없고 리터럴만 올 수 있다.
- case를 위한 constant와 enum
- 왜 enum을 사용하는 것이 권장되는가? enum을 사용하면 무슨 이점이 있는가? enum을 사용하는 경우 사전에 enum에 설정된 것만 사용할 수 있어서 개발자가 임의의 상수를 입력해서 사용할 수 없다.
- Loop
- while, do ~ while, for( ; ; ) for( : ) 상기 반복문에 대해서 알 고 있는가?
(enhanced for) - Mehotd
- 메서드를 실행할 때 값을 전달하는 방법을 알고 있는가?
- 메서드(
전달할 값(자주 변함)
) 전달할 값(고정됨)
.메서드
- 메서드(
- System.in
- 표준 입력 장치의 정보가 저장된 메모리의 주소를 보하고 있는 레퍼런스 테스트해보려면 wc 명령어를 터미널에서 사용해 볼 수 있다. (word count) wc 명령어 이후 키보드로 입력되는 정보는 표준입력장치의 주소(System.in)로 들어간다. 명령어 입력하고, aaa bbb ccc (엔터) ddd eee fff (엔터) (컨트롤 + D) 이렇게 입력을 주면 결과를 반환해준다. 라인수, 단어수, 글자수 순으로 값을 반환해준다.
- $ cat
- 파일을 읽고 연결해서(Concatanate) 해서 출력해준다. 표준입력장치를 이용하는 wc, cat 명령어로 어떤 파일의 라인수, 단어수, 글자수를 세 보자. cat Hello.c | wc
- | (Pipeline)
- 다음 명령어로 값을 넘겨준다. 자세한 내용을 다시 적기
표준입력장치는 키보드를 떠올릴 게 아니라 표준 통로라고 생각하는게 더 좋은 생각이다. 건물도 정문같이 표준 통로가 있듯이 데이터도 들어오고 나가는 표준 ‘통로’가 있다. 물론 그 통로가 아니어도 가능하다.
- 표준 스트림(Stream)
- 표준 입력 스트림과 표준 출력 스트림, 표준 오류 스트림이 있다. 모든 프로그램에는 크게 세가지의 통로가 있다. 이 통로를 스트림이라고 한다. 그 세가지는 표준 입력 스트림과 표준 출력 스트림, 표준 오류 스트림이 있다. 각각은 자바에서
System.in
,System.out
,System.err
이 된다
표준 입력 스트림은 단순히 키보드라고 말할 수 없다. 표준 입력 스트림에 다른 프로그램의 출력을 입력할 수도 있다.
표준 입력 스트림은 프로그램 외부에서 데이터가 들어올 수 있는 기본 입구이며, 표준 출력 스트림은 프로그램 실행 결과를 외부로 내보낼 수 있는 기본 출구이며, 표준 에러 스트림은 프로그램 실행 중 오류가 발생했을 때 오류 정보를 내보낼 때 사용하는 기본 출구이다. (좀 특별한 출구이다.)
어린이집의 대피용 미끄럼틀은 비상시 특별 출구라는 점에서 System.err이라고 할 수 있다.
표준 출력 스트림은 터미널로 연결이 가능하며, 다른 프로그램의 표준 입력 스트림과 연결도 가능하다. 파이프라인을 통해서, cat 명령어의 출력을 wc로 연결한 것처럼 말이다. 다른 에시로 출력을 파일과 연결시키면 파일로 출력이 된다.
1
2
3
4
# Hello.c 를 작성하고 아래로 표준 입력 스트림에 파이프라인을 통해 cat 명령어 결과르 ㄹ넣어보자. 키보드 입력이 아닌 다른 입력을 테스트해 볼 수 있다.
$ cat Hello.c | wc
$ cat Hello.c >> test.ok
$ cat test.ok
표준 입력, 출력, 오류 스트림이 아니면 프로그램의 데이터 입출력을 할 수 없는가?
아니다. 그냥 그 표준 스트림들은 표준일 뿐이다.
소켓 이라는 단어를 들어본 적 있는가? 프로그램 외부에 있는 네트워크와 입력과 출력을 하기 위해 별도의 입구, 출구를 뚫은 것이 소켓이다.
프로그램 외부에 있는 파일과 입출력을 위해서 구멍을 뚫을 수도 있다. 파일을 위한 입구, 출구를 뚫은 것은 File I/O Stream 이라고 한다. (구멍=입출구)
(참고로 실제 구멍을 뚫을 때는 입구와 출구를 각각 뚫어야 한다.)
- System.in.read()
- read(), read(byte[]) … 위 메서드에는 한 줄 단위로 입력된 문자열을 읽는 작업을 수행시키는 명령어가 없다. 그럼 어떻게 이 문제를 해결할 수 있을까?
- new Scanner ( — )
- 표준 입력 스트림을 좀 더 정교하게 제어하려면 추가적인 데이터와 도구가 필요하다. System.in에 추가 데이터와 도구(Method)를 제공해야 한다는 이야기다. 그것이 Scanner이다.
- Scanner
- Scanner는 무엇인가? nextLine(), nextInt(), next() 와 같은 줄 단위 입력을 편하게 해준다.
메서드의 실행(호출)에 대하여
1
Scanner keyIn = new Scanner(System.in);
다음과 같은 문장에 대하여 정확히 말하면 keyIn
은 Scanner
인스턴스의 주소를 가진 레퍼런스이다. 그러나 *더 편한 의사소통을 위하여* keyIn
을 Scanner
객체가 들어있는 변수 처럼 간주하여 의사소통한다.
- 예시
keyIn
객체에 대하여nextLine()
을 호출하라.
위 예시를 정확하게 말하면,
Scanner 객체의 nextLine() 메서드를 실행하기 위하여 해당 Scanner 인스턴스의 주소를 가지고 있는 Scanner Reference인 keyIn 을 이용하여 nextLine() 메서드를 호출하라.
라고 말하면 된다. 그러나 이것이 너무 길기에 줄여서 말하는 경우가 아주 많다. 메서드는 명령어, 함수라는 용어로도 많이 사용되며, 메서드의 호출은 메서드의 실행, 명령어의 실행, 명령어의 호출 등으로도 쓰인다.
- System.in
- System.in은 표준 입력 스트림에 관한 정보를 가지고 있는 메모리 주소를 가지고 있다.
1
java.util.Scanner keyScan = new java.util.Scanner(System.in);
위 라인을 설명해보자. Scanner 객체를 생성하여 인스턴스로 만든다. 그 때 System.id 이라는 객체의 주소를 가지고 있는 주소를 넘긴다. 이에 대한 주소는 레퍼런스인 keyScan에 저장된다.
nextInt() 는 한 개의 토큰을 읽을 때 까지 기다린다. (Blocking) 하나의 토큰을 읽으면, 그것을 4바이트 정수 값으로 바꾼 다음에 리턴한다. 토큰은 공백으로 구분는 단어를 말한다. 공백은 스페이스, 탭, 줄바꿈 코드를 말한다. 참고로, 공백이 여러개 있어도 한 개의 공백으로 간주하도록 설계되었다. 그래서 토큰단위로 읽는 메서드는 a b c 같이 공백으로 연결된 여러 값들을 입력해주는 경우 한번에 입력할 수 있다.
- wc
- wc 결과로 라인수, 단어수, 글자수라고 하는데 이 단어수가 토큰수다. 공백으로 구분되는 토큰의 개수를 두번째로 알려준다. 그러니까, 정확히 말하면 라인수, 토큰수, 글자수를 알려주는 것이다.
스캐너정보가담겨있는주소를줄테니까이주소에찾아가서nextLine()이라는작업을수행해! => Scanner객체에 대해 nextLine() 메서드를 호출해.
nextInt(), nextLine()
nextInt() 메서드를 호출하여 정수를 입력하고 줄바꿈(엔터) 한 경우 마지막에 0x0A 혹은 0x0D0A 가 붙는다. LF, CRLF 라고 부르는 줄바꿈을 말하는 유니코드다. nextInt는 정수까지 읽고 뒤에 붙은 줄바꿈 유니코드를 버리지 않는다. 그래서 nextInt() 이후에 이 입력들을 버리지 않으면 다음 입력 관련 메서드를 호출했을 때 스트림에서 들어간다. 이 문제를 해결하고자 한다면 간단한 방법으로 nextLine() 을 한번 수행해주면, 값을 버릴 수 있다. (어떤 변수에 굳이 넣지 않으면 그냥 버려진다.) 스트림에 읽어올 데이터가 없는 경우에 프로그램은 blocking 된다. 이것이 보통 원하는 결과일 것이다.
Method
코드 재사용성을 살리기 위함. 왜 재사용성에 분할하는 메서드가 중요한가? 코드 라인수가 많아지면 일단 읽기가 힘들어지고, 어떤 목적으로 작성된 건지 이해하기가 힘들어진다. 근데 메서드는 이름짓기도 하고, 한줄로 줄어드는 축약이 가능하기에 가독성도 좋아지고 이해하기도 쉬워진다. 그래서 이렇게 메서드로 꺼내는 것이 리팩토링 기법 중 하나이며, 이를 Method Extraction 이라고 한다.
변수의 종류
클래스 필드와 로컬 변수 변수를 구분하는 이 두 유형은 무엇인가? 각각의 변수는 언제 메모리에 로딩(사용)되며, 언제 사라지는가? 클래스 필드는 JVM이 생성되고 종료될 때 로컬 변수는 메소드가 호출되고 종료될 때
고민할거
이름 살려서 지메일 하나 파고 그걸로 깃허브 운영하는게 나을 거 같다. 쓰레기 메일들이 너무 많다.
한번에 잘 하려고 하지 마라
리팩토링은 왜 있는가? 작가는 왜 퇴고를 하는가? 모든 기술은 불완전하며 각 단점들을 개선하는 것이 역사다.
퇴고는 초고를 수정, 보완, 정리하는 작업이다. 리팩토링을 하지 않는 개발자는 초고만 하고 퇴고를 하는 작가는 작가가 아니다.
글쓰는 걸 두려워하는 작가는 한번에 잘 쓰려고 해서 그렇다.
코드 작성을 두려워하는 개발자는 한번에 완벽한 코드를 짜려고 해서 그렇다.
쫄지마라. 그냥 해봐라. 잘못 해도 괜찮다. 그것도 경험치다.
퇴고의 어원 퇴고는 당나라 시인 가도가 새는 못가 나무에 자고 중은 달빛 아래 문을 미는구나 라는 시구에서 퇴(밀다)에서 고(두드리다) 라는 어구 변경을 고민하였다는 일화에 어원이 있다.
퇴고에도 기술이 있다.
리팩토링에도 기술이 있다. 리팩토링 기법은 아주 많다. 100가지야 쉽게 넘어간다.
이름이 중요하다. 리팩토링이라는 이름이 붙으니까 단순한 고치기가 아니게 된다. POJO도 그렇다. Vanilia JS Programming 같은 이름도 그렇다. 리팩토링은 단순히 유지보수하는 것에서 그치는 것이 아니다. 리팩토링 기법을 정리해서 책으로 낸 사람이 있다. 켄트 백, 워드 커닝햄, 마틴 파울러와 같은 객체지향 세계의 신이 있다. 그 중에서 마틴 파울러가 낸 책이 있다. (워드 커닝햄은 위키를 만든 사람이다.)
https://www.aladin.co.kr/m/mproduct.aspx?ItemId=236186172 켄트 백과 마틴 파울러의 일화
1판은 Java 2판은 JavaScript로 예제가 있다.
고수가 되기 위해 읽어보자잉
과학자이면서 수학자면서 물리학자이면서 철학자이면서 논리학자인 과학자 개발자이면서 수학자이면서 철학자이면서 과학자인 개발자~