2021/01/22 - [공부/자바(java) 융합개발자 2차] - [자바 9일차] 28일차 - 컬렉션 프레임워크 (p.404~447)
쓰레드, I/O
Gugudan.java
package com.day10;
public class Gugudan {
public static void main(String[] args) {
Gugudan g1 = new Gugudan(5);
g1.print(); //5*1= 5 ..
}
}
=> 완성하기
package com.day10;
public class Gugudan {
private int dan;
public Gugudan(int dan) { //생성자
this.dan = dan;
}
public void print() {
for(int i = 1; i < 10; i++) {
System.out.println(dan + "*" + i + "=" + dan*i);
}
System.out.println();
}
public static void main(String[] args) {
Gugudan g1 = new Gugudan(5);
g1.print(); //5*1= 5 ..
}
}
==> 객체 더 만들어보기
==> 전체 코드
우리는 객체를 만들어서 print()라는 함수를 이용해 원하는 단의 구구단을 출력할 수 있다.
package com.day10;
//원하는 단을 출력하는 클래스
public class Gugudan {
int dan;
public Gugudan(int dan) { //생성자
this.dan = dan;
}
public void print() {
for (int i = 1; i < 10; i++) {
System.out.println(dan + "*" + i + "=" + dan * i);
}
System.out.println();
}
public static void main(String[] args) {
Gugudan g1 = new Gugudan(5);
g1.print(); // 5*1 = 5 하면서 해당하는 단 출력되록 할 것
Gugudan g2 = new Gugudan(6);
g2.print();
Gugudan g3 = new Gugudan(9);
g3.print();
}
}
==> 여기 까지는 충분히 할 수 있다. 그런데, 쓰레드란 무엇인가?
컴퓨터 : CPU라는 프로세스가 동작, 보통 하나의 프로세스
Thread : 가장 작은 실행 단위(프로세스를 좀 더 잘게 쪼게서)
- 지금 현재는 동작이 1개 : 단일 Thread
- 여러개 : 멀티 Thread
-> 컴퓨터가 여러개를 동시에 움직인다 ? 사실은 한번에 실행하는게 아니고 A,B,C,D 로 실행 되는데 우리는 한번에 실행하는 것처럼 보이는 것
- Java.lang : Thread라는 클래스가 있다 -> import하지 않아도 사용 가능
GugudanTh.java
우리가 구현해야할 것 : run()
우리는 run을 직접적으로 control할 수 없다.
.start()를 해주면 준비되어있는 Thread에 가서 실행한다.
그러나 Thread는 실행 단위를 최소로 쪼개놓은 것
- 각각 i가 1~9까지, gt1, gt2, gt3이 각각 9번씩 동작 시키는데 순서를 우리가 제어할 수 없다 -> 뒤죽박죽으로 나온다.
- 이전에는 gt1.start() 1~9까지 run() 돌림 -> gt2.start() 1~9까지 run() 돌림 -> gt3.start() 1~9까지 run() 돌림 순으로 실행이 되었는데
-> Thread는 실행 단위를 더더더더 가장 최소로 쪼개놓아 실행 시킴
-> 여러 객체가 함께 대화할 때처럼 : 동시에 실행(동시에 함께 대화)되는 것처럼 하려면 순서대로 객체1이 할말 다하고, 객체2가 할말 다하고.. 하는 등 하나씩 실행되는게 아니라 최소 단위(한 마디)를 실행시켜서 3개가 동시에 실행(3 객체가 앞 사람 말이 다~ 끝나기를 기다렸다가 자기 순서에 할말을 다 하는 것이 아니라 함께 이야기를 하는 것처럼)되는 것 같은 효과!
위에서는 Thread라는 클래스를 상속 받아서 사용 했는데,
Thread의 기능도 쓰고 다른 클래스를 상속받고 싶으면 어떻게 해야할까?
여기서 문제가 생김! 자바는 다중상속 불가능!
--> Thread 클래스를 상속받지 말고, interface Runnable이라는 것을 implements 해서 사용하면 됨
GugudanTh2.java
Thread 클래스의 함수 run()이라는 건 start()를 통해서 불러주어야 하는데,
현재는 Thread 클래스를 상속받아 사용하는 게 아니므로 start()로 접근 불가
가능하게 해주려면 run()에 접근하기 위해서는 Thread 클래스의 객체를 만들어서 그 객체를 통해 접근 해주어야 한다.
내가 출력을 하고 싶은 dan은 GugudanTh2의 객체 gth1만 알고 있고, Thread의 객체 t1은 모름
-> Thread t1 = new Thread(____); 여기 안에 해당 객체 gth1을 지정해 주어야 함
Threa(); ()안에는 구현할 객체 넣어주기
==> 5단을 출력 했으니 8단도 출력해보자.
Thread 사용 방법 2가지
1. 직접 Thread 클래스를 상속 받아서(extends Thread) -> run() 구현 후 main에서 start()로 호출해서 사용
2. interface Runnable을 implements -> run() 구현 -> main에서 run()에 접근하기 위해 Thread 클래스의 객체 생성 -> 생성한 Thread 클래스의 객체를 통해 start() 사용 -> run() 호출
Saram.java
사람 객체 3명 만들기
각각의 객체에 홍길동, 이순신, 강감찬 이라는 이름을 인수로 넣어주기
==> 오류 나지 않도록 하기
- 현재 디폴트 생성자(괄호 안이 빈 것)가 아니기 때문에 생성자 만들어주기
전역변수에 name을 두기
==> 사람 3명이 각각 5마디씩 말할 것(speak)
==> 에러 수정
==> speak() 채워주기 : 5마디씩 말 하도록
- 이때까지 우리 했던 것 -> 이렇게 되면 서로 말을 하는게 아니라 홍길동 혼자 5마디 하고 그 다음 차례인 이순신이 앞 사람 홍길동의 5마디가 끝날 때까지 기다린 후에 5마디 하고.. 이런 식.. : 대화XX
- 일단은 그대로 두고 헷갈리지 않도록 말의 순서를 붙여주기
==> SaramThread.java
- 이제 각자 일방적으로 5마디씩 이야기하는 게 아니고, 대화할 수 있도록 Thread 상속받아 구현하기
- 5번씩 말하기
- 홍길동, 이순신, 강감찬이 서로 끼어들어가지고 1~5번째 말을 할 수 있도록 함
-> 뒤죽박죽으로 나옴 -> 현재 순서 : 이순신 -> 강감찬 -> 강감찬 -> 홍길동.. 이렇게 막 실행됨
-> 객체 s1, s2, s3가 run()이라는 애를 서로 같이 공유해서 사용한다고 볼 수 있다.
-> 앞에서는 그냥 홍길동 -> 이순신 -> 강감찬이 순서대로 5번을 혼자 다 말하고 그 다음번 차례인 이순신이 또 혼자 5번 말하고.. 하는 식이었음!
==> 전체 코드
package com.day10;
public class SaramThread extends Thread { //Thread를 상속 받음
String name;
public SaramThread(String name) {
this.name = name;
}
@Override
public void run() { //run을 구현해 주어야 함
for(int i = 1; i < 6; i++) {
System.out.println(name + ":" + i + "번째 말하다.");
}
}
public static void main(String[] args) {
SaramThread st1 = new SaramThread("홍길동");
SaramThread st2 = new SaramThread("이순신");
SaramThread st3 = new SaramThread("강감찬");
st1.start();//상속받은 메서드 run()은 start()를 통해서 불러야 함
st2.start();
st3.start();
}
}
SaramRun.java
- 이번에는 Thread 클래스를 상속받는게 아니라 interface Runnable을 이용하여 구현하기
-> 상속받는 것이 아니라 interface를 이용함!
==> 전체 코드
package com.day10;
public class SaramRun implements Runnable { //인터페이스 이용
private String name;
public SaramRun(String name) {
this.name = name;
}
@Override
public void run() { //인터페이스에서 구현되지 않은 run 구현해주어야 함 -> 호출 : start()
for(int i = 1; i < 6; i++) {
System.out.println(name + "이 " + i + "번째 말한다.");
}
}
public static void main(String[] args) {
SaramRun sr1 = new SaramRun("홍길동"); //Thread 클래스를 상속 받은 것이 아니므로 SaramRun객체가 직접 start()로 run() 호출 불가
Thread t1 = new Thread(sr1); //Thread 객체를 만들고
t1.start(); //Thread 객체를 통해 start()로 run()에 접근
SaramRun sr2 = new SaramRun("이순신");
Thread t2 = new Thread(sr2);
t2.start();
SaramRun sr3 = new SaramRun("강감찬");
Thread t3 = new Thread(sr3);
t3.start();
}
}
- 직접적으로 start()를 부르지 못하고 Thread 클래스의 객체를 만들어서 -> start() -> run() 호출
- Thread 객체의 인자 값으로 내가 만든 객체 sr을 집어넣음!!
* Thread를 쓸 때 주의할 점
- 위에서 보면 run()을 3개의 객체가 같이 공유해서 쓴다고 볼 수 있음
- 그러나 함께 움직이면 안되는 경우가 있을 수 있음
ex) 영화 예매에서 자리 자치의 경우!
- 예매하는 행위는 자체는 누구나 동시에 접근해서 할 수 있어야 함!
-> 우리가 영화 예매를 할 때 예매 페이지에 접근해서 하는데, 누가 예매하는 중이면 예매 자체를 못하고 끝날 때까지 기다렸다가 차례가 되면 예매를 할 수 있는 등 순서대로 예매 행위가 이루어지면 안 됨 -> 즉, 함수 '예매하다'는 동시에 실행 가능해야 함
- But! 예매하는 행위 자체는 동시에 하더라도 각기 다른 객체가 동일한 자리에 동시에 똑같이 예매가 되어버리면 안 됨
-> Thread를 통해 '예매하다'는 동시에 진행하지만 자리 배정은 동시에 이루어지지 않도록! 조치를 취해야 함
ex) 계좌 이체 : 내가 타인에게 이체를 하면 내 계좌에서는 마이너스가 되고 받는 사람의 계좌에는 플러스가 되는 일련의 과정
- Thread로 동시에 가능한 행위 : 이체를 하려고 접근해서 금액 정하는 등 행위
- Thread로 동시에 하면 안되는 행위 : 내가 10만원을 java라는 사람의 계좌에 이체를 하고 있는데, 동시에 100만원을 java라는 사람의 계좌에 이체하려고 시도 -> 그럼 결과적으로 내 통장에는 10만원이 빠져나가야 하는가, 100만원이 빠져나가야 하는가, 또, java라는 사람의 계좌에는 10만원이 +되는가(잔액은 얼마가 남는가) 100만원이 +되는가.. -> 두개가 짬뽕이 되어버림.. -> 조치를 취해야 함!
이 조치가 바로 '동기화'
-> 동기화를 구현해야 한다!
아래 두 가지는 비슷하지만 각각 Vector, Hashtable은 ArrayList와 HashMap과 다르게 동기화 구현O
ArrayList(동기화 구현X) vs. Vector(동기화 구현O)
- 두 가지가 비슷하나 Vector가 좀 더 안정적임
HashMap(동기화 구현X) vs. Hashtable(동기화 구현O)
- 두 가지가 비슷하나 Hashtable이 좀 더 안정적임
SynchEx.java
==> 학생 클래스와 게시판 클래스 생성
- 보니까 학생들은 동시에 게시판에 글을 쓸 수 있다.
- 그러나 게시판에는 순서대로 글이 올라가야 할 듯!
==> 객체 생성 : 게시판, 학생, Thread 객체
- 학생 객체는 이름을 인자로 갖고, Board에 접근 가능하도록 Board의 객체도 인자로 가짐
==> 각 객체는 동일한 게시판 Board b에 접근함
==> 오류 없애기
- 게시판 : 한 사람이 10씩 더할 수 있다
==> 게시글 수 10개 증가시키기!
- 이순신, 홍길동 이라는 학생이 게시판에 10번씩 접근 가능
- 뒤죽박죽으로 결과 나옴!
당연히 sth1과 sth2가 run을 같이 공유
- 누가 게시판에 접근했는지 모름..
==> 누가 접근했는지 보자
- 보면 0과 1이 start를 통해 run에 접근하는 것은 동시에 가능 -> 그러나 0이 add를 실행하고 있는데 실행을 마치기 전에 1이 접근해서 run이 또 실행되면서 뒤죽박죽으로 결과가 나옴
(학생0, 1이 동시에 게시판에 접근 가능 -> 그러나 학생0이 게시판에 글을 쓰고 업로드를 하고 있는데 이걸 마치기 전에 학생1도 접근해서 쓴 글을 동시에 업로드 하면 뒤죽박죽이 됨)
-> 내가 실행을 마치기 전(업로드를 끝내기 전)에는 다른 사람이 업로드 하지 못하도록 해주자 : synchronized
->
- 게시판에 접속해서 글 쓰는 것은 동시에 가능 : Thread
- 업로드는 동시에 작동되면 뒤죽박죽이 됨(Thread로 동시에 작동하면 곤란한 것) : synchronized 사용
-> 내가 업로드 중일 때 접근 X, 완료되면 다음 사람이 업로드하라!
음 내가 설명한게 좀 이상한듯!(업로드.. 글 10개.. 이런거!)
예외처리
- 예상되어지는 오류
ExceptionTest01.java
배열 길이는 3인데 0~9까지 10번을 돌려서 msg[0]~msg[9]까지 출력해달라고 요구해보자.
- 있는 0, 1, 2의 내용은 출력해주고 그 뒷부분은 당연히 에러 발생 : 배열의 범위를 벗어났다. 없는 배열인데 출력하라고 한다. 에러 종류 : ArrayIndexOutOfBoundsException
for는 0~9까지 돌리되 try-catch문으로 0~2범위(존재하는 범위이면) try 속 내용을 실행하고 배열의 범위를 벗어나서 ArrayIndexOutOfBoundsException 에러가 발생하면 catch 속 내용을 실행 : 예외 처리
- try를 수행하다가 예외가 발생하면 오류를 띄우지 말고 catch 속 내용을 수행함
- String str의 내용이 없는데(null인데) str에 저장된 문자열의 길이를 출력해달라고 해보자
- str은 아직 만들어지지 않았는데 str의 길이를 출력하겠다? 당연히 오류가 남
- 이 때 오류는 NullPointerException으로 catch에는 걸리지 않음 : 왜냐하면
내가 특정한 에러는 ArrayIndexOutBoundsException으로 배열의 범위를 초과한 경우만을 말함
즉 다른 범위의 예외가 발생 한 것 -> 이것도 예외처리를 해보자.
즉, catch 여러 개 가능
- finally는 예외가 하지 않았어도 반드시 수행하는 문장
Exception02.java
당연히 배열의 크기 3 보다 더 크게 돌려서 에러 남!
-> try-catch문 말고 다른 걸로 예외처리를 해보자.
- 오류가 발생하는 부분 -> main부분
-> thorws로 해당 예외를 던져 버림
-> 다른 에러를 하나 더 발생시켜보기
->
이렇게도 예외처리를 해줄 수 있다.
그러나 아직 아무 처리도 해주지 않아서 여전히 에러 표시는 발생함
I/O
1. 단방향
Input Output
- 입력을 위한 객체가 따로 있고, 출력을 위한 객체가 따로 있다.
- 하나의 객체로 입력, 출력 둘 다 불가능
2. 기반 : 스트림 기반, 문자 기반
- 스트림 기반 ==> Stream(바이트 흐름 : 입, 출력의 기본적인 형태)
-> 그러나 바이트 만으로는 부족
- 문자 기반
입력 출력
Reader Wirter가 최상위 (못들음!)
3. 표준 입력과 출력
- 표준입력 : console로 읽어들이는 것 : System.in(우리가 이때까지 입력 받은 방식)
Scanner sc = new Scanner(System.in);
- 표준출력 : 모니터에 출력 : System.out
Sytem.out.println();
여기서 in이라는 객체는 형태가 InputStream
자바에서 만들어준 필드가 이미 존재함
read는 입력 관련 -> I/O Exception이 발생한다.
오류가 발생할 수 있다는 걸 자바가 예측하고 알려줌 -> 예외처리를 하라는 뜻
read()는 반환값이 int형인데.. 모두 읽어들이고 나면 -1을 반환
입력값이 출력될 때 아스키코드로 나옴.. 문자로 출력하고싶다.
입력하는 그대로 나옴
한글 입력하면 깨짐 1바이트씩 입력받고 반환하는 거라서 2바이트인 한글은 깨짐
==> 한글처리 해주기
콘솔창에 우리가 입력한 것을 기반으로 만들어 진다.
콘솔 창에서 문자 입력받는 경우 이렇게 하면 되고 콘솔에서 입력받지 않고 파일을 읽어들일경우!
=> FileTest01.java
- Gugudan.java 파일을 읽어들일 것
Gugudan.java를 읽어들여보자!
자바에서는 역슬래쉬를 표현하기 위해 두번 써주어야 함
파일이 없는 경우도 존재하므로 예외처리 넣어주기
==>
FileTest01.java에서 Gugudan 말고 ExceptionTest01.java 읽어보기
한글 깨짐 -> 1바이트씩 읽고 내보내고 하는데 한글은 2바이트가 모여야 되므로 깨짐
finally는 반드시 하는게 좋음
==> 한글깨지지 않도록 ! 해주기
FileTest02.java
읽어들이는 것 문자 기반 : Reader
파일로 읽어들일 것 -> FileReader
==> 출력 해보기
==> finally 해주는게 좋음
fr.close();로 닫아 주기!
==> FileTest03.java : 파일로 읽어들이고, 파일로 내보낸다.
실행시 콘솔 창에는 아무 것도 안 뜸
경로를 안적어주고 result.text라고만 적어주면 경로는 Project 아래가 된다.
==> 콘솔 창으로 내보내고 싶다!
==> txt파일에서는 한글이 안깨지는데, 콘솔창에는 한글이 깨짐 -> 1바이트씩 처리해서 내보내는데 한글은 2바이트가 모여 이루어진 것이기 때문
자바는 클래스가 잘 만들어져 있다.
FileTest04.java
1. GugudanTh.java를 읽어서
2. gugu.text로 보내기
3. try-catch 사용
실행하면
파일이 생성됨
==> 지금은 int형밖에 안됨.. 내가 만약 한 줄을 읽어야 한다면?
javja.io > Classes > BufferedInputstream 또는 BufferedReader
Buffer 한번에 모아서 저장하겠다.
ex) Gugudan.java 파일에서 번호를 붙이고 내용을 출력하는 형태로 만들기
-> 한 줄씩 읽어와야 한다는 뜻
-> BufferedReader를 쓰면 된다.
FileTest05.java
출력한 결과물에 문장의 번호를 찍어주고 싶다.
한 줄씩 읽어들이는 다른 방법 : Scanner로도 가능
-> 한 줄씩 읽어들이는데 읽어들이는 형태가 int형이 아니라 다양한 형태라면.. Reader로는 안됨
-> Scanner 사용
-> 이걸 하나의 파일로 생각을 못하고 "src\~~"를 한 줄의 문자로 생각함
->
파일 객체로! 만들어 주는데 FileNotFoundException이 발생할 수 있음
==> 하나의 파일로 내보내보자
앞에서는 write를 통해 int형으로 내보냈음 -> 우리는 한 줄을 내보낼 수 있어야 함
PrintStream 사용
println()은 다양한 형태를 출력 가능
==> Buffered 이용해도 괜찮고, Scanner 이용해도 됨!
output.txt
aa.txt 만들기
New > File > aa.txt
Tokenfile.java 만들기
1. aa.txt 파일을 읽어서
2. 16진수로 변환해서 -> bb.txt로 내보내기
3. 단, 문자열의 split(":"); 함수 이용
-> :의 앞, 뒤로 분리해서 생각을 하고싶으면 '10:20'을 한 줄씩 읽어와야 함
==> aa.txt를 한 줄씩 읽어들여서
==> : 으로 나누어서
==> 16진수로 변환
==> bb.txt로 내보내기
TokenFile02.java
aa.txt 파일을 읽어서
8진수로 변환하여 cc.txt로 내보내기
단, StringTokenizer이용
-> aa.txt를 한줄씩 읽어들여 : 나누어 이를 8진수로 변환하여
//cc.txt로 내보내기
phone.txt 만들기
PhoneFile.java
==>
이름, 전화번호를 따로 분리해서 저장할 건데 어디에 저장하는게 맞을까?
==> load()
==> search()
다르게 표현 가능
==> sava()
==>
예전에 나라, 수도 맞추는 게임에서는 우리가 나라, 수도를 입력해도 다음 실행하면 날라갔는데
이렇게 파일로 만들어서 저장하면 추가해주고 싶은 애들을 입력 받아서 파일로 저장하기 때문에
날라가지 않음
지난번 com.day09의 CapitalApp.java 참고해서 MyCapital.java만 들기
나라, 수도 목록은 capital.txt에 따로 만들어주기
==> input()
이전에는 우리가 입력해줬다면 이번에는 capital.txt 파일을 읽어올 것!
프로그램을 실행하면 가장 먼저 실행되는 것에 map이 추가 되도록 해야 함
- 가장 먼저 실행되는 것 -> new 해줬으니 생성자가 실행되는데 여기서 디폴트 생성자가 없으므로 만들어주기
헷갈리면 변수에 담기!
이제는 나라, 수도를 적어서 문제를 더 만들면 없어지지 않고 저장된다.
'프로그래밍 > 자바(java) 융합개발자 2차' 카테고리의 다른 글
[toString() 재정의] (0) | 2021.04.12 |
---|---|
[자바] 21.02.05 JUnit, assertEquals, path 잡기 (0) | 2021.02.05 |
[자바 9일차] 28일차 - 컬렉션 프레임워크 (p.404~447) (0) | 2021.01.22 |
[자바 8일차] 27일차 - String 클래스(p.369~) (0) | 2021.01.21 |
[자바 7일차] 26일차 - 상속, 추상클래스, 추상메서드 , 인터페이스(Do it 공부단 p.234~) (0) | 2021.01.20 |