|
Back-End/Java 2019. 4. 21. 18:31
-입력 스트림과 출력 스트림-
프로그램이 데이터를 입력받을 때에는 입력스트림(InputStream)이라고 부르고, 프로그램이 데이터를 보낼 때에는 출력스트림(OutputStream)이라고 부른다.
-콘솔 입출력-
콘솔은 시스템을 사용하기 위해 키보드로 입력을 받고 화면으로 출력하는 소프트웨어를 말한다. 자바는 콘솔로부터 데이터를 입력받을 때 System.in을 사용하고, 콘솔에 데이터를 출력할 때 System.out를 사용한다. 그리고 에러를 출력할 때에는 System.err을 사용한다.
-System.in 필드-
콘솔로부터 데이터를 입력받을 수 있도록 System클래스의 in정적 필드를 제공하고 있다. System.in은 InputStream 타입의 필드이므로 InputStream 변수로 참조가 가능하다.
InputStream is System.in;
read()메소드로 입력된 바이트를 읽으면 아스키 코드가 들어있다. 키보드에서 입력한 문자를 직접 얻고 싶다면 read() 메소드로 읽은 아스키 코드를 char로 타입 변환하면 된다.
char inputChar = (char) is.read();
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 |
package com.hs.chap18;
import java.io.IOException;
import java.io.InputStream;
public class SystemInExample1 {
public static void main(String[] args) throws Exception {
System.out.println("== 메뉴 ==");
System.out.println("1. 예금 조회");
System.out.println("2. 예금 출금");
System.out.println("3. 예금 입금");
System.out.println("4. 종료 하기");
System.out.println("메뉴를 선택하세요: ");
InputStream is = System.in; //키보드 입력 스트림 얻기
char inputChar = (char) is.read(); //얻은 아스키 코드를 문자로 리턴
switch (inputChar) {
case '1':
System.out.println("예금 조회를 선택하셨습니다.");
break;
case '2':
System.out.println("예금 출금을 선택하셨습니다.");
break;
case '3':
System.out.println("예금 입금을 선택하셨습니다.");
break;
case '4':
System.out.println("종료하기를 선택하셨습니다.");
break;
}
}
}
|
cs |
-System.out 필드-
콘솔로 데이터를 출력하기 위해서 사용하는 필드. out는 PrintStream 타입의 필드이다.
OutputStream os = System.out;
-Console 클래스-
콘솔에서 입력받은 문자열을 쉽게 읽을수 있도록 하는 클래스. 이클립스에서 실행하면 System.console() 메소드는 null을 리턴하기 때문에 반드시 명령 프롬프트에서 실행해야 한다.
-Scanner 클래스-
Console 클래스는 콘솔로부터 문자열은 읽을 수 있지만 기본타입(정수,실수) 값을 바로 읽을 수는 없다. Scanner 클래스를 이용하면 콘솔로부터 기본 타입의 값을 바로 읽을 수 있다. Scanner 객체를 생성하려면 생성자에 System.in 매개값을 주면 된다.
Scanner scanner = new Scanner(System.in);
-FileInputStream-
파일로부터 바이트 단위로 읽어드릴때 사용하는 바이트 기반 입력 스트림이다. 바이트 단위로 읽기 때문에 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 읽을 수 있다.
//첫번째 형식
FileInputStream fis = new FileInputStream("C:/Temp/image.gif"); //문자열로된 파일의 경로를 가지고 생성
//두번째 형식
File file = new File("C:/Temp/image.gif"); FileInputStream fis = new FileInputStream(file);
-FileWriter-
텍스트 데이터를 파일에 저장할 때 사용하는 문자 기반 스트림.
-예제 및 출력결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
package com.hs.chap18;
import java.io.File;
import java.io.FileWriter;
public class FileWriterExample {
public static void main(String[] args) throws Exception {
File file = new File("C:/Temp/file.txt"); // C:/Temp/file.txt경로에 txt파일을 만든다.
FileWriter fw = new FileWriter(file, true);
fw.write("FileWriter는 한글로된" + "/r/n");
fw.write("문자열을 바로 출력할 수 있다." + "/r/n");
fw.flush(); // 출력 버퍼에 있는 데이터를 파일로 완전히 출력
fw.close(); // 파일을 닫는다.
System.out.println("파일에 저장되었습니다.");
}
}
|
cs |
Back-End/API 2019. 4. 21. 17:08
-java.io 패키지-
자바의 기본적인 데이터 입출력 API 제공 파일 시스템의 정보를 얻기위한 File 클래스와 데이터를 입출력하기 위한 입출력 스트림 클래스를 제공 스트림 클래스는 두종류로 나뉜다. 하나는 바이트(byte)기반 스트림이다. 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 받고 보낼수 있다. 다른 하나는 문자(character)기반 스트림이다. 문자 기반 스트림은 오로지 문자만 받고 보낼 수 있도록 되어있다.
-InputStream-
바이트 기반 입력 스트림의 최상위 클래스로 추상클래스이다. 바이트 기반 입력 스트림은 이 클래스를 상속받아서 만들어진다.
1. read() 메소드
입력 스트림으로부터 1바이트를 읽고 4바이트 int 타입으로 리턴한다. 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴한다.
2.read(byte[]b) 메소드
입력 스트림으로부터 매개값으로 주어진 바이트 배열의 길이만큼 바이트를 읽고 배열에 저장한다. 그리고 읽은 바이트 수를 리턴한다. 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴한다.
3.read(bytep[]b,int off, int len) 메소드
read(bytep[]b,int off, int len) 메소드는 입력 스트림으로부터 len개의 바이트만큼 읽고, 매개값으로 주어진 바이트 배열 b[off]부터 len개까지 저장한다. 그리고 읽은 바이트 수인 len개를 리턴한다. 또한 read(byte[]b)와의 차이점은 한 번에 읽어들이는 바이트 수를 len 매개값으로 조절 할 수 있고, 배열에서 저장이 시작되는 인덱스를 지정할 수 있다. 만약 off를 0으로, len을 배열의 길이로 준다면 read(byte[]b)와 동일하다.
4.close() 메소드
InputStream을 더 이상 사용하지 않을 경우에 시스템 자원을 풀어주는 메소드.
-OutputStream-
바이트 기반 출력 스트림의 최상위 클래스로 추상클래스이다. 바이트 기반 출력 스트림은 이 클래스를 상속받아서 만들어진다.
1.write(int b) 메소드
write(int b)메소드는 매개 변수로 주어진 int값에서 끝에 있는 1바이트만 출력 스트림으로 보낸다.
2.write(byte[]b) 메소드
write(byte[]b)는 매개값으로 주어진 바이트 배열의 모든 바이트를 출력 스트림으로 보낸다.
3. write(bytep[]b,int off, int len) 메소드
write(bytep[]b,int off, int len)은 b[off]부터 len개의 바이트를 출력 스트림으로 보낸다.
4.flush() 메소드
버퍼에 잔류하고 있는 데이터를 모두 출력시키고 버퍼를 비우는 역할을 한다. 프로그램에서 더 이상 출력할 데이터가 없다면 flush() 메소드를 마지막으로 호출하여 버퍼에 잔류하는 모든 데이터가 출력되도록 해야 한다.
5.close() 메소드
InputStream을 더 이상 사용하지 않을 경우에 시스템 자원을 풀어주는 메소드.
-Reader-
문자 기반 입력 스트림의 최상의 클래스로 추상클래스이다 모든 문자 기반 입력 스트림은 이 클래스를 상속받아서 만들어진다.
-Writer-
문자 기반 출력스트림의 최상의 클래스로 추상클래스이다 모든 문자 기반 출력 스트림은 이 클래스를 상속받아서 만들어진다.
Back-End/Java 2019. 4. 20. 21:13
-스트림(Stream)-
컬렉션 (배열포함)의 저장 요소를 하나씩 참조해서 람다식(함수적-스타일)로 처리할 수 있도록 해주는 반복자이다. Stream은 Iterator과 비슷한 역할을 하는 반복자이지만, 람다식으로 요소 처리 코드를 제공하는 점과 내부 반복자를 사용하므로 병렬 처리가 쉽다는점, 그리고 중간 처리와 최종 처리 작업을 수행하는 점에서 차이를 가지고 있다.
-외부 반복자-
개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드. index를 이용하는 for문 그리고 Iterator를 이용하는 while문 등이 있다.
-내부 반복자-
컬렉션 내부에서 요소들을 반복시키고, 개발자는 요소당 처리해야 할 코드만 제공하는 코드 패턴을 말한다. 내부 반복자를 사용해서 얻는 장점은 컬렉션 내부에서 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맞겨두고, 개발자는 요소 처리 코드에만 집중할 수 있다는 것이다.
-병렬 처리-
한 가지 작업을 서브 작업으로 나누고, 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는 것을 말한다.
-스트림 파이트라인-
스트림은 데이터의 필터링, 매핑, 정렬, 그룹핑 등의 중간 처리와 합계, 평균, 카운팅, 최댓값. 최소값 등의 최종 처리를 파이프라인으로 해결한다. 파이프라인은 여러개의 스트림이 연결되어 있는 구조를 말한다. 파이프라인에서 최종 처리를 제외하고는 모두 중간 처리 스트림이다. 중간 스트림이 생성될 때 요소들이 중간 처리(필터링, 정렬 등) 되는 것이 아니라 최종 처리가 시작되기 전까지 중간 처리는 지연된다. 최종 처리가 시작되면 비로소 컬렉션의 요소가 하나씩 중간 스트림에서 처리되고 최종 처리까지 오게 된다.
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 |
package com.hs.chap16;
public class Member {
public static int MALE = 0;
public static int FEMALE = 1;
private String name;
private int sex;
private int age;
public Member(String name, int sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public int getSex() {
return sex;
}
public int getAge() {
return age;
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 |
package com.hs.chap16;
import java.util.Arrays;
import java.util.List;
public class StreamPipelinesExample {
public static void main(String[] args) {// Arrays.asList 메소드를 사용해서 새로운 객체를 생성해 list에 넣어준다.
List<Member> list = Arrays.asList(new Member("홍길동", Member.MALE, 30), new Member("김나리", Member.FEMALE, 20),
new Member("신용권", Member.MALE, 45), new Member("박수미", Member.FEMALE, 27)
);
double ageAvg = list.parallelStream().filter(m -> m.getSex() == Member.MALE).mapToInt(Member::getAge).average()
.getAsDouble(); // 매개변수 m의 getsex()메소드를 호출해 그 값이 MALE와 같은것만 필터링하고, Member 객체를 age 값으로 매핑해 age를
// 요소로 갖는 스트림을 생성하고 그 평균을 계산하고, 그 값을 읽기위해 getAsDouble()메서드를 호출해서 그 값을 읽고,
// ageAvg에 저장한다.
System.out.println("남자 평균 나이: " + ageAvg);
}
}
|
cs |
-필터링-
필터링은 중간 처리 기능으로 요소를 걸러내는 역할을 한다. 필터링 메소드인 distinct()와 filter() 메소드는 모든 스트림이 가지고 있는 공통 메소드이다.
distinct() 메소드는 중복을 제거하는데 equals를 사용해 true면 동일한 객체로 판단하고 중복을 제거한다.
filter() 메소드는 매개값으로 주어진 Predicate가 true를 리턴하는 요소만 필터링한다.
-매핑-
매핑(mapping)는 중간 처리 기능으로 스트림의 요소를 다른 요소로 대체하는 작업을 말한다.
flatMapXXX() 메소드는 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림을 리턴한다.
A -> A1,A2
B -> B1,B2
mapXXX() 메소드는 요소를 대체하는 요소로 구성된 새로운 스트림을 리턴한다.
A -> C B -> D
-정렬-
스트림은 요소가 최종 처리되기 전에 중간 단계에서 요소를 정렬해서 최종 처리 순서를 변경할 수 있다.
-루핑-
루핑은 요소 전체를 반복하는 것을 말한다. 루핑하는 메소드에는 peek(), forEach()가 있다.
peek()는 중간 처리 단계에서 전체 요소를 루핑하면서 추가적인 작업을 하기 위해 사용한다. 또한 최종 처리 메소드가 호출되어야 동작한다.
intStream .filter( a -> a%2 == 0) .peek( a -> System.out.println(a) ) .sum()
하지만 forEach()는 최종 처리 메소드이기 때문에 파이프라인 마지막에 루핑하면서 요소를 하나씩 처리한다.
-집계-
최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등과 같이 하나의 값으로 산출하는 것
-수집-
스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메소드인 collect()를 제공하고 있다.
이 메소드를 이용하면 필요한 요소만 컬렉션으로 담을 수 있고, 요소들을 그룹핑한 후 집계 할 수 있다.
List<Student> maleList = totalList.stream( )
.filter(s -> s.getSex() == Student.Sex.MALE)
.collect(Collectors.toList( ) );
-예제 및 출력결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 |
package com.hs.chap16;
public class Student {
public enum Sex {
MALE, FEMALE
}
public enum City {
Seoul, Pusan
}
private String name;
private int score;
private Sex sex;
private City city;
public Student(String name, int score, Sex sex) {
this.name = name;
this.score = score;
this.sex = sex;
}
public Student(String name, int score, Sex sex, City city) {
this.name = name;
this.score = score;
this.sex = sex;
this.city = city;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public Sex getSex() {
return sex;
}
public City getCity() {
return city;
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 |
package com.hs.chap16;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ToListExample {
public static void main(String[] args) {
List<Student> totalList = Arrays.asList(
new Student("홍길동",10,Student.Sex.MALE),
new Student("김수애",6,Student.Sex.FEMALE),
new Student("신용권",10,Student.Sex.MALE),
new Student("박수미",6,Student.Sex.FEMALE)
);
//남학생들만 묶어 List 작성
List<Student> maleList = totalList.stream()
.filter(s->s.getSex() == Student.Sex.MALE)
.collect(Collectors.toList());
maleList.parallelStream()
.forEach(s->System.out.println(s.getName()));
System.out.println();
//여학생들만 묶어 HashSet 생성
Set<Student> femaleSet = totalList.stream()
.filter(s->s.getSex() == Student.Sex.FEMALE)
.collect(Collectors.toCollection(HashSet :: new));
femaleSet.stream()
.forEach(s-> System.out.println(s.getName()));
}
}
|
cs |
-동시성-
멀티 작업을 위해 멀티 스레드가 번갈아가며 실행하는 성질
-병렬성-
멀티 작업을 위해 멀티 코어를 이용해서 동시에 실행하는 성질
-데이터 병렬성-
데이터 병렬성은 전체 데이터를 쪼개어 서브 데이터들로 만들고 이 서브 데이터들을 병렬 처리해서 작업을 빨리 끝내는 것을 말한다. 예를 들어 쿼드 코어 CPU일 경우 4개의 서브 요소들로 나누고, 4개의 스레드가 각각의 서브 요소들을 병렬 처리한다.
-작업 병렬성-
작업 병렬성은 서로 다른 작업을 병렬 처리하는 것을 말한다.
작업 병렬성의 대표적인 예는 웹 서버이다.
웹 서버는 각각의 브라우저에서 요청한 내용을 개별 스레드에서 병렬로 처리한다.
-병렬 스트림-
parallelStream( ) 메소드는 컬렉션으로부터 병렬 스트림을 바로 리턴한다.
parallel( ) 메소드는 순차 처리 스트림을 병렬 처리 스트림으로 변환해서 리턴한다.
Back-End/API 2019. 4. 20. 17:36
-IntStream-
기본 타입인 int 요소를 처리하는 스트림.
Arrays.stream(int[])
IntStream.range(int,int)
IntStream.rangeClosed(int,int)
-LongStream-
기본 타입인 Long 요소를 처리하는 스트림.
Arrays.stream(long[])
LongStream.range(long,long)
LongStream.rangeClosed(long,long)
-DoubleStream-
기본 타입인 Double 요소를 처리하는 스트림.
Arrays.stream(Double[])
Back-End/JSP 2019. 4. 19. 20:53
Back-End/Java 2019. 4. 19. 16:47
-컬렉션 프레임 워크-
객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 java.util 패키지에 컬렉션과 관련된 인터페이스와 클래스들을 포함시켜 놓은것을 컬렉션 프레임 워크라고 한다. 컬렉션 프레임 워크의 주요 인터페이스로는 List,Set,Map가 있다.
(배열을 사용하면 다수의 객체를 저장하고 삭제했을 때 해당 인덱스가 비게되고, 새로운 객체를 저장하려면 어디가 비어 있는지 확인하는 코드도 필요하기 때문이다)
-List 컬렉션-
객체를 인덱스로 관리하기 때문에 객체를 저장하면 자동 인덱스가 부여되고 인덱스로 객체를 검색, 삭제할 수 있는 기능을 제공한다. List 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 번지를 참조 한다.
-ArrayList-
일반 배열과 ArrayList는 인덱스로 객체를 관리한다는 점에서는 유사하지만, 배열은 생성할 때 크기가 고정되고 사용 중에 크기를 변경할 수 없지만, ArrayList는 저장용량(capacity)을 초과한 객체들이 들어오면 자동적으로 저장용량이 늘어난다. 빈번한 객체 삽입과 삭제가 일어나는 곳에서는 ArrayList를 사용하는 것이 바람직하지 않다. (ArrayList는 중간에 객체가 삭제되면 뒤에 있는 객체들이 전부다 한칸씩 앞으로 옮겨야 하는 등, 효율적이지 않기 때문이다.)
또한 size()는 컬렉션 타입의 길이를 확인할때 사용하고, length는 배열의 길이를 알려할때 사용한다. 즉 ArrayList에서는 length를 사용할 수 없다.
list<String> list = new ArrayList<String>(); //컬렉션 생성 list.add("홍길동"); //컬렉션에 객체를 추가 String name = list.get(0); //컬렉션에서 객체 검색, 홍길동을 바로 얻음
고정된 객체들로 구성된 List를 생성할 때는 다음과 같이 사용한다.
List<T> list = Arrays.asList(T...a); //제네릭 사용
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
package com.hs.chap15;
import java.util.*; // *은 util디렉토리 안에 있는 모든 클래스를 사용하겠다는 말입니다.
public class ArrayListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("java"); // add는 객체를 저장한다.
list.add("이한섭");
list.add("5");
int size = list.size(); // 저장된 총 객체수를 얻는다.
System.out.println("배열에 저장된 총 객체수 : " + list.size()); // add로 넣은 list에 총 3개의 문자열이 있기 때문에 3이 출력된다.
list.add(3, "영창"); // 인덱스 번호 3번에 영창이라는 문자열을 추가한다.
for (int i = 0; i < list.size(); i++) {
System.out.println("배열에 저장되어 있는 값 : " + list.get(i));
}
System.out.println("2번째 인덱스에 저장되어 있는 값 : " + list.get(2));
list.remove(1); // 1번 인덱스를 삭제
list.remove(2); // 2번 인덱스를 삭제
for (int i = 0; i < list.size(); i++) {
System.out.println("1번과 2번 인덱스 삭제한 배열에 저장되어 있는 값 : " + list.get(i));
}
}
}
|
cs |
-제네릭 타입 <E>-
타입파라미터라고 부른고,컴파일 할때 해당 타입이 일치하는지 확인할 수 있어, 좀 더 오류를 발생시키지 않고 안전하게 사용할 수 있게 하기 위해 사용한다.
-Vector-
ArrayList와 동일한 내부 구조를 가지고 있고, Vector를 생성하기 위해서는 저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출하면 된다.
ArrayList와 다른점은 동기화된(synchronized) 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할수 없고,
하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다.
그렇기 때문에 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있다.
List<E> list = new Vector<E>();
-LinkedList-
LinkedList는 List 구현 클래스이므로 ArrayList와 사용방법은 같지만 내부구조는 다르다. ArrayList는 내부 배열에 객체를 저장해서 인덱스로 관리하지만, LinkedList는 인접 참조를 링크해서 체인처럼 관리한다.
LinkedList를 생성하기 위해서는 저장할 객체 타입을 타입 파라미터(E)에 표기하고 기본 생성자를 호출하면 된다. 또한 처음 생성될때는 어떠한 링크도 만들어지지 않기 때문에 내부는 비어 있다고 보면 된다.
List<E> list = new LinkedList<E>();
-Set 컬렉션-
List 컬렉션은 저장 순서를 유지하지만, Set 컬렉션은 저장 순서가 유지되지 않는다. 또한 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있다. Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드(get())가 없다.
Iterator() 메소드 = 전체 객체를 대상으로 한번씩 반복해서 가져온다.
next() 메소드 = 하나의 객체를 가져올 때 사용.
hasNext() 메소드 = 가져올 객체가 있으면 true를 리턴하고, 더 이상 가져올 객체가 없으면 false를 리턴한다.
-HashSet-
HashSet는 객체를 저장하기 전에 먼저 hashCode()메소드를 호출해서 해시코드를 얻어낸다. 그리고 이미 저장되어 있는 객체들의 해시코드와 비교한다. 만약 동일한 해시코드가 있다면 다시 equals() 메소드로 두 객체를 비교한다. true가 나오면 동일한 객체로 판단하고 중복저장을 하지 않는다.
-Map 컬렉션-
Map 컬렉션은 키(key)와 값(value)으로 구성된 Entry 객체를 저장하는 구조를 가지고 있다. 여기서 키와 값은 모두 객체이다. 키는 중복 저장될 수 없지만 값은 중복 저장될 수 있다. 만약 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대치된다.
ex) HashMap<String, Integer> a = new HashMap<String, Integer>(); //키와 값을 받아야 하기 때문에 제네릭 타입을 <String, Integer> 두개를 설정
a.put("one",1); //키 값을 one, value 값을 1로 설정 System.out.println(a.get("one")); //키(key)인 one를 호출하면 그 키의 값(value)인 1이 출력이 된다.
-예시-
Map 컬렉션은사우나의 물품보관함과 비슷한 개념을 가진다. - 물품보관함의 번호는 순서대로 있지만 열쇠(키)가 없으면 물품을 보관을 할 수가 없다. - 중복된 열쇠는 허용하지 않으며 물품은 중복이 가능해도 된다. •위 처럼 열쇠(키)와 물품(값)으로 구성된 자료구조를 Map계열 컬렉션이라고 한다. •Map계열에서 키는 유니크해야한다.
HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); - HashMap컬렉션은 생성형태는 intger를 키로사용하고 String을 값으로 사용했다.
•hashMap.put(0, "str0"); - List계열과는 달리 put메소드를 이용해 데이터를 추가한다.
•hashMap.remove(2); - 여기서 "2"는 키를 의미한다. - 2번 키를 삭제한다.
•hashMap.clear(); - 컬렉션에 담은 키와 값을 전체 삭제한다. - 아직은 메모리에 연결된 상태로 추가를 할 수 있다.
•Iterator<Integer> iterator = hashMap.keySet().iterator(); - Iterator 인터페이스는 반복적인 데이터를 검색하는데 유용하다. - hashMap.keySet() 메소드를 이용해 반복적인 작업을 수행한다.
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 |
package com.hs.chap15;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapExample {
public static void main(String[] args) {
// Map 컬렉션 생성
Map<String, Integer> map = new HashMap<String, Integer>(); // 맵 컬렉션으로 키와 값을 받기 위해 키는 String, 값은 Integer 타입을
// 선언한다.
// 객체 저장
map.put("신용권", 85); // 키 와 값을 저장
map.put("홍길동", 90);
map.put("동장군", 80);
map.put("홍길동", 95); // "홍길동" 키가 같기 때문에 2번째 저장한 값은 마지막에 저장한 값으로 대치된다.
System.out.println("총 Entry 수: " + map.size());
// 객체 찾기
System.out.println("/t홍길동 : " + map.get("홍길동")); // 홍길동 이라는 키로 값을 검색한다.
System.out.println();
// 객체를 하나씩 처리
Set<String> keySet = map.keySet(); // 키를 얻는 keyset 메소드로 키를 얻어서 keyset에 저장한다.
Iterator<String> keyIterator = keySet.iterator(); // 모든 키값을 불러와서 keyIterator에 저장
while (keyIterator.hasNext()) // 키를 한개씩 불러온다.
{
String key = keyIterator.next();
Integer value = map.get(key);
System.out.println("/t" + key + ":" + value); // 키 4개중에 홍길동은 위에서 중복되었기 때문에 키가 3개만 출력이 된다.
}
System.out.println();
// 객체 삭제
map.remove("홍길동"); // 키 3개중에서 1개가 삭제되었기 때문에 2개가 남는다.
System.out.println("총 Entry 수 : " + map.size()); // 남은 키는 2개이기 때문에 size()의 값은 2개가 된다.
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
Iterator<Map.Entry<String, Integer>> entryIterator = entrySet.iterator();
while (entryIterator.hasNext()) // 위에서 처럼 키를 얻어 저장된 값을 출력한다.
{
Map.Entry<String, Integer> entry = entryIterator.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("/t" + key + " : " + value); //남은 키는 2개이기 때문에 해당 키에 해당되는 값 2개가 출력이 된다.
}
System.out.println();
// 객체 전체 삭제
map.clear(); //남은 2개의 키가 삭제 되었기 때문에 남은 Entry의 수는 0개가 된다.
System.out.println("총 Entry 수: " + map.size());
}
}
|
cs |
-Hashtable-
Hashtable는 HashMap와 동일한 내부 구조를 가지고 있다.
Hashtable도 키로 사용할 객체는 hashCode()와 equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 한다.
HashMap과의 차이점은 Hashtable은 동기화된(synchronized) 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할 수는 없고, 하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다.
형식 : Map<K, V> map = new Hashtable<K, V>( );
-Properties-
Properties는 Hashtable의 하위 클래스이기 때문에 Hashtable의 모든 특징을 그대로 가지고 있다.
차이점으로는 Hashtable는 키와 값을 다양한 타입으로 지정이 가능한데 비해 Properties는 키와 값을 String 타입으로
제한한 컬렉션이다.
주로 애플리케이션의 옵션 정보, 데이터베이스 연결 정보, 그리고 프로퍼티 파일을 읽을 때 주로 사용한다.
-이진 트리 구조-
여러개의 노드(node)가 트리 형태로 연결된 구조. 루트 노드라고 불리는 하나의 노드에서 시작해 각 노드에 최대 2개의 노드를 연결할 수 있는 구조를 가지고 있다. 위아래로 연결된 두 노드를 부모-자식관계에 있다고 하여 위의 노드를 부모 노드, 아래의 노드를 자식 노드라고 한다. 하나의 부모 노드는 최대 두 개의 자식 노드와 연결 될 수 있다. 또한 작은 값은 왼쪽에, 큰 값은 오른쪽에 저장한다. 숫자가 아닌 문자를 저장할 경우에는 문자의 유니코드 값으로 비교한다.
왼쪽 마지막 노드에서부터 오른쪽 마지막 노드까지[왼쪽 노드 -> 부모 노드 -> 오른쪽 노드] 순으로 읽으면 오름차순으로 정렬된 값을 얻을수 있고,
오른쪽 마지막 노드에서부터 왼쪽 마지막 노드까지[오른쪽 노드 -> 부모 노드 -> 왼쪽 노드] 순으로 읽으면 내림차순으로 정렬된 값을 얻을수 있다.
-TreeSet-
TreeSet는 이진트리를 기반으로한 Set 컬렉션이다. 하나의 노드는 노드값인 value와 왼쪽과 오른쪽 자식 노드를 참조하기 위한 두개의 변수로 구성된다.
부모값과 비교해서 낮은 것은 왼쪽 자식 노드에, 높은 것은 오른쪽 자식 노드에 저장한다.
TreeSet를 생성하기 위해서는 저장할 객체 타입을 파라미터로 표기하고 기본 생성자를 호출하면 된다.
TreeSet<E> treeSet = new TreeSet<E>( );
String 객체를 저장하는 TreeSet은 다음과 같이 생성할 수 있다.
TreeSet<String> treeSet = new TreeSet<String>( );
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 |
package com.hs.chap15;
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<Integer>();
scores.add(new Integer(87));
scores.add(new Integer(98));
scores.add(new Integer(75));
scores.add(new Integer(95));
scores.add(new Integer(80));
Integer score = null;
score = scores.first(); // TreeSet의 first()메소드는 가장 낮은 값을 리턴한다.
System.out.println("가장 낮은 점수: " + score);
score = scores.last(); // TreeSet의 first()메소드는 가장 낮은 값을 리턴한다.
System.out.println("가장 큰 점수: " + score);
score = scores.lower(new Integer(95)); // TreeSet의 lower()메소드는 매개값보다 낮은 객체를 리턴한다.
System.out.println("95점 아래 점수: " + score);
score = scores.higher(new Integer(95)); // TreeSet의 Integer()메소드는 매개값보다 큰 객체를 리턴한다.
System.out.println("95점 위의 점수: " + score);
score = scores.floor(new Integer(95)); // TreeSet의 floor()메소드는 매개값보다 작은 바로 아래 객체를 리턴한다.
System.out.println("95점 이거나 바로 아래 점수: " + score);
score = scores.ceiling(new Integer(85)); // TreeSet의 ceiling()메소드는 매개값보다 작은 바로 아래 객체를 리턴한다.
System.out.println("85점 이거나 바로 위의 점수: " + score);
while (!scores.isEmpty()) {
score = scores.pollFirst();
System.out.println(score + "(남은 객체 수: " + scores.size() + ")");
}
}
}
|
cs |
-TreeMap-
TreeMap는 이진 트리를 기반으로 한 Map 컬렉션이다. TreeSet와의 차이점은 키와 값이 저장된 Map.Entry를 저장한다는 점이다.
기본적으로 부모 키 값과 비교해서 키 값이 낮은 것은 왼쪽 자식 노드에, 키 값이 높은 것은 오른쪽 자식 노드에 Map.Entry 객체를 저장한다.
TreeMap<K, V> treeMap = new TreeMap<K, V>( ); // K는 키 타입, V는 값 타입
-LIFO 와 FIFO-
후입선출(LIFO)은 나중에 넣은 객체가 먼저 빠져나가는 자료구조를 말한다.
선입선출(FIFO)은 먼저 넣은 객체가 먼저 빠져나가는 구조.
-Stack-
Stack 클래스는 LIFO 자료구조를 구현한 클래스이다.
Stack<E> stack = new Stack<E>( );
-Queus-
Queue 인터페이스는 FIFO 자료구조에서 사용되는 메소드를 정의하고 있다.
다음은 Queue 인터페이스에 정의되어 있는 메소드를 보여준다.
Quesu 인터페이스를 구현한 대표적인 클래스는 LinkedList이다.
LinkedList는 List 인터페이스를 구현했기 때문에 List 컬렉션이기도 하다.
Queue<E> queue = new LinkedList<E>( );
Back-End/Java 2019. 4. 18. 18:08
-람다식-
람다식을 사용하는 이유는 자바 코드가 매우 간결해지고, 컬렉션의 요소를 필터링 하거나 매핑해서 원하는 결과를 쉽게 집계할 수 있기 때문이다.
Runnable 인터페이스의 익명 구현 객체를 생성하는 코드
Runnable runnable = new Runnable(){ public void run(){........} //익명 구현 객체 }
익명 구현 객체를 람다식으로 표현한 코드 Runnable runnable = (타입 매개변수) -> {실행문.......}; <- 람다식
-> 기호는 타입 매개 변수를 이용해서 중괄호{실행문}블록을 실행한다는 뜻으로 이해하면 된다. 만약 실행문에 return문만 있으면 중괄호는 생략할 수 있다. ex) (x,y) -> x + y
-익명 구현 객체-
-말 그대로 이름이 없는 객체. -단독 생성이 불가능 해서 클래스를 상속하거나 인터페이스를 구현해야만 생성이 가능하다. -익명 구현 객체를 사용하면 인터페이스를 구현한 클래스를 따로 만들 필요가 없게 되어 더 간결하게 인터페이스를 구현할 수 있다.
ㄴ형식 : new 클래스명() {내용} 이렇게 사용한다.
-타겟 타입-
인터페이스는 직접 객체화할 수 없기 때문에 구현 클래스가 필요한데, 람다식은 구현 클래스를 생성하고 객체화 한다. 람다식은 대입될 인터페이스의 종류에 따라 작성 방법이 달라지기 때문에 람다식이 대입될 인터페이스를 람다식의 타겟 타입이라고 한다.
-함수적 인터페이스-
람다식은 하나의 메소드만 정의하기때문에 두개 이상의 추상 메소드가 선언된 인터페이스는 람다식을 사용해 구현 객체를 생성할 수 없다. 하나의 추상 메소드가 선언된 인터페이스만이 람다식의 타겟 타입이 될 수 있는데, 이러한 인터페이스를 함수적 인터페이스라고 한다. 함수적 인터페이스를 작성할때 컴파일러가 두 개 이상의 추상 메소드가 선언되지 않도록 체킹해주는 기능이 있는데 인터페이스 선언시 @Functionallnterface 어노테이션을 붙이면 된다. 어노테이션은 두 개 이상의 추상 메소드가 선언되면 컴파일 오류를 발생시킨다.
-예제 및 출력 결과-
|
package com.hs.chap14;
public interface MyFunctionalInterface {
public void method();
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 |
package com.hs.chap14;
public class MyFunctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface fi;
fi = () -> {
String str = "method call1";
System.out.println(str);
//람다식으로 fi필드에 저장될 method메소드의 실행문을 적어준다.
};
fi.method(); //fi의 메소드를 호출하면 위에서 람다식으로 작성한 실행문이 출력된다.
fi = () -> {
System.out.println("method call2");
};
fi.method();
fi = () -> System.out.println("method call3");
fi.method();
}
}
|
cs |
-예제 및 출력결과-
(매개변수가 있는 추상메소드 정의)
|
package com.hs.chap14;
public interface MyFunctionalInterface {
//매개 변수가 있는 추상 메소드 정의
public void method(int a);
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 |
package com.hs.chap14;
public class MyFunctionalInterfaceExample {
// 추상메소드 매개변수에 들어갈 값을 설정.
private static int a = 5;
public static void main(String[] args) {
MyFunctionalInterface fi;
// 람다식으로 fi필드에 저장될 method메소드의 실행문과 매개변수를 적어준다.
fi = (a) -> {
String str = "매개변수가 들어간 람다식 실행";
System.out.println(str);
System.out.println("나의 이름은" + a + "글자 입니다.");
};
fi.method(a); // fi의 메소드를 호출하면 위에서 람다식으로 작성한 실행문이 출력된다.
}
}
|
cs |
-예제 및 출력결과-
(매개변수와 리턴값이 있는 추상메소드 정의 및 호출)
|
package com.hs.chap14;
public interface MyFunctionalInterface {
//두개의 매개 변수가 있는 추상 메소드 정의, 리턴값 없음
public int method(int a, int b);
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
package com.hs.chap14;
public class MyFunctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface fi;
// 람다식으로 fi필드에 저장될 method메소드의 매개변수로 a,b를 선언하고, a+b의 값을 리턴해서 fi필드에 저장한다.
fi = (a, b) -> {
int result = a + b;
return result;
};
System.out.println(fi.method(5, 10)); // fi의 method에 5,10을 주고 출력하면 method가 호출되서 두수를 더한값이 출력된다.
}
}
|
cs |
-추상 메소드-
매개변수와 리턴값이 없는 메소드
-클래스 멤버와 로컬변수를 람다식으로 사용-
일반적으로 익명 객체 내부에서 this는 익명 객체의 참조이지만, 람다식에서 this는 내부적으로 생성되는 익명 객체의 참조가 아니라 람다식을 실행한 객체의 참조이다.
-디폴트 메소드-
인터페이스에 신규 메소드를 모든 구현 클래스 수정 없이 추가하고자 할때 사용한다. 인터페이스에 디폴트 메소드를 추가하고 Override하고 싶은 클래스만 구현하여 실행할 수 있다. 디폴트 메소드를 가진 인터페이스를 상속받을 때 추상 메소드로 재선언이 가능하다.
-로컬 변수-
메소드 안에 선언한 변수이고, 매소드의 매개 변수 또는 로컬 변수를 사용하면 이 변수는 final 특성을 가져야 한다. 그렇기 때문에 람다식 내부 또는 외부에서 로컬변수를 변경할 수 없다.
하지만 메소드 블록 내부에서 사용하는 것은 가능하다.
(이유 : 변수의 값이 변하는 것을 원치 않아서 메소드 내부에 변수 선언을 하게 되는데 시스템에서 이러한 특성때문에 메소드 내부에 선언된 변수는 fianl 타입으로 자동적으로 인식되서 메소드 밖에서 변환 할수가 없게끔 되는것이다.)
-Consumer 함수적 인터페이스-
리턴값이 없는 accept() 메소드를 가지고 있다. accept() 메소드는 단지 매개값을 소비하는 역할만 한다. 여기서 소비한다는 말은 사용만 할 뿐 리턴값이 없다는 뜻이다.
-Supplier 함수적 인터페이스-
매개 변수가 없고 리턴값이 있는 getXXX() 메소드를 가지고 있다. 실행 후 호출한 곳으로 데이터를 리턴(공급)하는 역할을 한다.
-Predicate 함수적 인터페이스-
매개 변수와 boolean 리턴값이 있는 testXXXX() 메소드를 가지고 있다. 이 메소드들은 매개값을 조사해서 true 또는 false를 리턴하는 역할을 한다.
-andThen()와 compose()디폴트 메소드-
andThen()와 compose()디폴트 메소드 두개의 함수적 인터페이스를 순차적으로 연결하고, 첫 번째 처리 결과를 두 번째 매개값으로 제공해서 최종 결과값을 얻을때 사용한다.
인터페이스AB = 인터페이스A.andThen(인터페이스B); 최종결과 = 인터페이스AB.method();
andThen() 메소드는 인터페이스 AB의 method()를 호출하면 우선 인터페이스A 부터 처리하고 결과를 인터페이스B의 매개값으로 제공한다. 인터페이스B는 제공받은 매개값을 가지고 처리한 후 최종 결과를 리턴
compose() 메소드는 인터페이스AB의 method()를 호출하면 인터페이스 B부터 처리하고 결과를 인터페이스A의 매개값으로 제공한다. 인터페이스A는 제공받은 매개값을 가지고 처리한 후 최종 결과를 리턴한다.
-Predicate 종류 함수적 인터페이스-
and() 메소드 : 두 Predicate가 모두 true를 리턴하면 최종적으로 true를 리턴하는 Predicate를 생성한다.
or() 메소드 : 두 Predicate 중 하나만 true를 리턴하더라도 최종적으로 true를 리턴하는 Predicate를 생성한다.
negate() 메소드 : 원래 Predicate의 결과가 true이면 false로, false면 true를 리턴하는 새로운 Predicate를 생성한다.
isEqual() 메소드 : test() 매개값인 sourceObject와 isEqual()의 매개값인 targetObject를 Objects 클래스의 equals()의 매개값으로 제공하고, equals(sourceObject,targetObject)의 리턴값을 얻어 새로운 Predicate<T>를 생성한다.
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
package com.hs.chap14;
import java.util.function.Predicate;
public class PredicateIsEqualExample {
public static void main(String[] args) {
Predicate<String> predicate;
predicate = Predicate.isEqual(null);
System.out.println("null과 null은"+predicate.test(null));
predicate = Predicate.isEqual("Java");
System.out.println("Java와 null은"+predicate.test(null));
}
}
|
cs |
-정적 메소드와 인스턴스 메소드 참조-
정적 메소드를 참조할 경우에는 클래스 이름 뒤에 : : 기호를 붙이고 정적 메소드 이름을 기입한다.
클래스 : : 메소드
인스턴스 메소드일 경우에는 먼저 객체를 생성한 다음 참조 변수 뒤에 : : 기호를 붙이고 인스턴스 메소드 이름을 기술하면 된다.
참조변수 : : 메소드
-예제 및 출력 결과-
1
2
3
4
5
6
7
8
9
10
11
12 |
package com.hs.chap14;
public class Calculator {
public static int staticMethod(int x, int y) {
return x + y;
}
public int instanceMethod(int x, int y) {
return x + y;
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 |
package com.hs.chap14;
import java.util.function.IntBinaryOperator;
public class MethodReferencesExample {
public static void main(String[] args) {
IntBinaryOperator operator;
// 정적 메소드 참조
operator = (x, y) -> Calculator.staticMethod(x, y); // 람다식 사용
System.out.println("결과1: " + operator.applyAsInt(1, 2)); // x,y값에 각각 1과 2를 주어서 더한값을 출력함.
operator = Calculator::staticMethod; // staticMethod(정적메소드)를 참조
System.out.println("결과2: " + operator.applyAsInt(3, 4)); // x,y값에 각각 3과 4를 주어서 더한값을 출력함.
// 인스턴트 메소드 참조
Calculator obj = new Calculator();
operator = (x, y) -> obj.instanceMethod(x, y); // 람다식 사용
System.out.println("결과3:" + operator.applyAsInt(5, 6)); // x,y값에 5와 6을 넣어서 더한값 출력
operator = obj::instanceMethod; // instanceMethod(인스턴스 메소드)를 참조
System.out.println("결과4:" + operator.applyAsInt(7, 8)); // x,y값에 7과 8을 넣어서 더한값 출력
operator = (x, y) -> obj.instanceMethod(x, y); // 람다식 사용
System.out.println("결과3:" + operator.applyAsInt(5, 6)); // x,y값에 5와 6을 넣어서 더한값 출력
}
}
|
cs |
-중요 예제-
http://www.java2s.com/Tutorials/Java/java.util.function/Consumer/index.htm
Back-End/Data Base 2019. 4. 17. 20:30
|