스트림 - 요소를 하나씩 처리
•
peek() 메소드는 스트림을 반환하는 메소드로 중간 처리 메소드이다.
•
Looping 메소드에는 peek()와 forEach()가 있다.
◦
peek( ) 메소드는 스트림을 반환하는 메소드로 중간 처리 메소드이고, forEach( ) 메소드는 void를 반환하는 최종 처리 메소드이다.
◦
즉, peek( )는 최종 처리가 뒤에 붙지 않으면 동작하지 않는다.
package com.stream;
import java.util.Arrays;
public class LoopExample {
public static void main(String[] args) {
int[] intArr = {1, 2, 3, 4, 5};
int total = Arrays
.stream(intArr)
.filter(i -> i % 2 == 0)
.peek(System.out::println)
.sum();
System.out.println("총합 : " + total);
Arrays
.stream(intArr)
.filter(i -> i % 2 == 1)
.forEach(System.out::println);
}
}
Java
복사
스트림 - 요소 조건 만족 여부 (매칭)
•
요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능이다.
•
allMatch(), anyMatch(), noneMatch() 메소드가 있다.
package com.stream2;
import java.util.Arrays;
import java.util.stream.IntStream;
public class MatchExample {
public static void main(String[] args) {
int[] intArr1 = { 2, 4, 6, 8 };
int[] intArr2 = { 2, 3, 4, 6, 8 };
// 모두 2의 배수이면 true를 반환
boolean allEvenResult1 = Arrays.stream(intArr1).allMatch(i -> i % 2 == 0);
boolean allEvenResult2 = IntStream.of(intArr2).allMatch(i -> i % 2 == 0);
System.out.println("1번 배열이 모두 짝수인가? " + allEvenResult1);
System.out.println("2번 배열이 모두 짝수인가? " + allEvenResult2);
// 하나라도 홀수가 있으면 true를 반환
boolean anyOddResult1 = Arrays.stream(intArr1).anyMatch(i -> i % 2 == 1);
boolean anyOddResult2 = IntStream.of(intArr2).anyMatch(i -> i % 2 == 1);
System.out.println("1번 배열 중 하나라도 홀수가 있는가? " + anyOddResult1);
System.out.println("2번 배열 중 하나라도 홀수가 있는가? " + anyOddResult2);
// 10의 배수가 없으면 true를 반환
boolean notInTenTimes1 = Arrays.stream(intArr1).noneMatch(i -> i % 10 == 1);
boolean notInTenTimes2 = IntStream.of(intArr2).noneMatch(i -> i % 10 == 1);
System.out.println("1번 배열 중에는 10의 배수가 없는가?" + notInTenTimes1);
System.out.println("2번 배열 중에는 10의 배수가 없는가?" + notInTenTimes2);
}
}
Java
복사
스트림 - 요소 기본 집계
•
집계(Aggregate)는 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등과 같이 하나의 값으로 산출하는 것을 말한다.
•
대량의 데이터를 가공해서 하나의 값으로 축소하는 리덕션(Reduction)이라고 볼 수 있다.
•
컬렉션 요소는 동적으로 추가되는 경우가 많다.
•
만약 컬렉션에 요소가 존재하지 않으면 집계 값을 산출할 수 없으므로 NoSuchElementException 예외가 발생한다.
•
Optional 클래스는 집계값만을 저장하는 것이 아니라, Optional 클래스가 제공하는 메소드로
집계값이 존재하지 않을 경우, 디폴트 값을 설정하거나, 집계값을 처리하는 Consumer를 등록할 수 있다.
스트림 - 요소 커스텀 집계
•
reduce() 메소드, 스트림에 요소가 없을 경우 예외를 발생시킨다.
•
하지만 매개변수로 identity 매개값을 추가하면, 해당 값을 초기값으로 하기 때문에 예외를 발생시키지
않는다.
@Data
@AllArgsConstructor
public class Student {
private String name;
private int score;
}
public class ReductionExample2 {
public static void main(String[] args) {
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("박명수", 60));
studentList.add(new Student("유재석", 100));
studentList.add(new Student("정준하", 40));
int sum1 = studentList.stream().mapToInt(Student::getScore).sum();
System.out.println(sum1);
int sum2 = studentList.stream().mapToInt(Student::getScore).reduce(0, (a, b) -> a + b);
System.out.println(sum2);
}
}
Java
복사
스트림 - 요소 수집
•
스트림은 요소들을 중간 처리(필터링, 매핑)한 후 요소들을 수집하여 최종 처리 메소드인 collect() 메소드를 제공한다.
•
이 메소드 활용하여 필요한 요소만을 컬렉션에 담을 수 있으며, 요소들을 그룹핑하여 집계도 할 수 있다.
package com.stream4;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CollectExample {
public static void main(String[] args) {
List<Beverage> bList = new ArrayList<>();
bList.add(new Beverage("아이스 아메리카노", 1500, true));
bList.add(new Beverage("아이스 아메리카노", 1500, true));
bList.add(new Beverage("따뜻한 바닐라 라떼", 3500, false));
bList.add(new Beverage("제로콜라", 2000, true));
bList.add(new Beverage("솔의눈", 2000, true));
bList.add(new Beverage("실론티", 1500, true));
// 2000원의 음료
List<Beverage> two$List = bList.stream().filter(b -> b.getPrice() == 2000).collect(Collectors.toList());
// bList.stream().filter(b -> b.getPrice() == 2000).toList();
System.out.println(two$List);
System.out.println();
// 음료수 이름 길이가 3인 것들
Set<Beverage> threeSet = bList.stream().filter(b -> b.getName().length() == 3).collect(Collectors.toSet());
System.out.println(threeSet);
// 음료 이름, 가격으로 구성된 것들
Map<String, Integer> iceMap = bList.stream()
.distinct()
.filter(b -> b.isIce()).collect(Collectors.toMap(b -> b.getName(), b -> b.getPrice()));
System.out.println();
System.out.println(iceMap);
}
}
Java
복사
스트림 - 요소 그룹핑
•
스트림에서 제공하는 collect( ) 메소드는 단순히 요소를 수집하는 기능 이외에 컬렉션의 요소들을 그룹핑해서 Map 객체를 생성하는 기능도 있다.
•
collect( ) 메소드의 매개변수에 Collectors.groupingBy( ) 메소드에서 얻은 Collector를 제공하면 된다.
package com.stream4;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// 카테고리 상품 코드에 참고
public class CollectExample2 {
public static void main(String[] args) {
List<Beverage> bList = new ArrayList<>();
bList.add(new Beverage("따뜻한 아메리카노", 1500, false));
bList.add(new Beverage("따뜻한 바닐라 라떼", 3500, false));
bList.add(new Beverage("핫초코", 3500, false));
bList.add(new Beverage("제로콜라", 2000, true));
bList.add(new Beverage("솔의눈", 2000, true));
bList.add(new Beverage("실론티", 2000, true));
Map<String, Boolean> newBList = bList.stream()
.distinct()
.collect(Collectors.toMap(b -> b.getName(), b -> b.isIce()));
System.out.println(newBList);
System.out.println("============");
Map<Boolean, List<Beverage>> isIceMap = bList.stream()
.collect(Collectors.groupingBy(b -> (Boolean) b.isIce()));
for (Map.Entry<Boolean, List<Beverage>> entry : isIceMap.entrySet()) {
System.out.println(entry.getKey() + " : ");
for (Beverage b : entry.getValue()) {
System.out.println("\t" + b);
}
}
List<Beverage> iceList = isIceMap.get(true);
List<Beverage> hotList = isIceMap.get(false);
System.out.println(iceList);
System.out.println(hotList);
}
}
Java
복사
•
Collectors.groupingBy( ) 메소드는 그룹핑 후 매핑 및 집계를 할 수 있도록, 두번째 매개값으로 Collector를 가질 수 있다.
•
두 번째 매개값으로 사용되어 Collector를 얻을 수 있는 Collectors의 정적 메소드들은 아래와 같다.
입출력 스트림
•
데이터는 키보드를 통해 입력될 수도 있고, 파일 또는 타 프로그램으로부터 입력될 수도 있다.
•
반대로 모니터로 출력될 수도 있고, 파일에 저장되거나 타 프로그램으로 전송될 수 있다.
•
이것들을 총칭해서 데이터 입출력이라고 한다.
•
스트림(Stream)은 단방향으로 동작한다.
•
프로그램 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 된다.
•
프로그램에서 다른 프로그램과 데이터를 교환하기 위해서는 양쪽 모두 입력 스트림과 출력 스트림이 필요하다.
•
스트림 종류
◦
바이트 스트림: 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용한다.
◦
문자 스트림: 문자만 입출력할 때 사용
◦
package com.file;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
public class FileExample3 {
public static void main(String[] args) throws IOException {
// image.jpg 파일을 복사하여, image2.jpg 만들기
String inputPath = "/Users/haminsung/Desktop/test/java/image.jpg";
String outputPath = "/Users/haminsung/Desktop/test/java/image2.jpg";
// 파일 복사
FileInputStream fr = new FileInputStream(inputPath);
FileOutputStream fw = new FileOutputStream(outputPath);
byte[] buffer = new byte[1024];
int bytesRead;
while((bytesRead = fr.read(buffer)) != -1) {
fw.write(buffer, 0, bytesRead);
}
fr.close();
fw.flush();
fw.close();
}
}
Java
복사
입출력 스트림 - 바이트 스트림 (출력)
•
모든 바이트 출력 스트림 클래스는 OutputStream 클래스를 상속받아 만들어진다.
◦
FileOutputStream
◦
PrintStream
◦
BufferedOutputStream
◦
DataOutputStream
package com.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) throws FileNotFoundException {
try {
OutputStream os = new FileOutputStream("/Users/haminsung/Desktop/test/java/output.txt");
byte a = 65;
byte b = 66;
byte c = 67;
// os.write(a);
// os.write(b);
// os.write(c);
// byte[] arr = { 68, 69, 70, 71, 72, 73 };
// os.write(arr);
byte[] arr = { 65, 66, 67, 76, 79, 86, 69 }; // ABCLOVE
os.write(arr, 3, 4);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
복사
입출력 스트림 - 바이트 스트림 (입력)
•
InputStream은 바이트 입력 스트림의 최상위 클래스인데, 추상 클래스이다.
•
모든 바이트 입력 스트림 클래스는 InputStream 클래스를 상속받아 만들어진다.
◦
(FileInputStream, BufferedInputStream, DataInputStream)
•
InputStream 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메소드가 정의되어 있다.
입출력 스트림 - 문자 스트림 (출력)
•
모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아 만들어진다.
◦
FileWriter, BufferedWriter, PrintWriter, OutputStreamWriter
package com.write;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample {
public static void main(String[] args) {
try {
Writer w = new FileWriter("/Users/haminsung/Desktop/test/java/output.txt");
char a = 'A';
w.write(a);
char[] arr1 = { 'B', 'C', 'D' };
w.write(arr1);
char[] arr2 = { 'C', 'D', 'E', 'F', 'G' };
String str1 = "HIJK";
String str2 = "JKLMNOP";
w.write(arr2, 2, 3);
w.write(str1);
w.write(str2, 2, 5);
w.flush();
w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
복사
입출력 스트림 - 문자 스트림 (입력)
•
Reader는 문자 입력 스트림의 최상위 클래스인데, 추상 클래스이다.
◦
모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아 만들어진다.
◦
FileReader, BufferedReader, InputStreamReader
package com.read;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReadExample {
public static void main(String[] args) {
try {
Reader r = new FileReader("/Users/haminsung/Desktop/test/java/output.txt");
// while (true) {
// int data = r.read();
// if (data == -1) break;
// System.out.println((char) data);
// }
char[] cArr = new char[16];
while (true) {
int num = r.read(cArr);
if (num == -1) break;
}
for (char c : cArr) {
System.out.println(c);
}
r.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
복사
입출력 스트림 - 보조 스트림
•
자체적으로 입출력을 수행할 수 없으므로 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.
입출력 스트림 - 성능 향상 스트림 (버퍼)
•
네트워크로 데이터 전송 시 느린 네트워크 환경이라면 컴퓨터 사양이 아무리 좋아도 메신저와 게임 속도는 느리다.
•
중간에 메모리 버퍼(Buffer)와 작업함으로써 실행 성능을 향상시킬 수 있다.
•
버퍼는 데이터가 쌓이기를 기다렸다가 꽉 차게 되면, 데이터를 한꺼번에 하드 디스크로 보낸다. 이로 인해 출력 횟수를 줄여준다.
BufferedInputStream bis = new BufferedInputStream(바이트입력스트림);
BufferedOutputStream bos = new BufferedOutputStream(바이트출력스트림);
BufferedReader br = new BufferedReader(문자입력스트림);
BufferedWriter bw = new BufferedWriter(문자출력스트림);
Java
복사
•
문자 입력 스트림 Reader에 BuffereReader를 연결하면 성능 향상 뿐만 아니라, readLine() 메소드도 제공한다. readLine( ) 메소드는 행 단위 문자열을 읽기 때문에 매우 편리하다.
package com.buffer;
import java.io.*;
public class BufferExample {
public static void main(String[] args) {
// 복사할 파일과 복사될 파일의 경로 지정
String inputPath = "/Users/haminsung/Desktop/test/java/input.txt";
String outputPath = "/Users/haminsung/Desktop/test/java/output.txt";
try {
// 파일 읽기 위한 BufferedReader
BufferedReader br = new BufferedReader(new FileReader(inputPath));
// 파일 쓰기 위한 BufferedWriter
BufferedWriter bw = new BufferedWriter(new FileWriter(outputPath));
String line;
while (true) {
line = br.readLine();
if (line == null) {
break;
}
bw.write(line);
bw.newLine(); // 각 라인마다 새로운 줄 추가
}
// 파일의 각 줄을 읽는다.
while ((line = br.readLine()) != null) {
bw.write(line); // 읽은 줄을 출력파일에 작성
bw.newLine(); // 각 라인마다 줄바꿈 추가
}
bw.flush();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java
복사
입출력 스트림 - File과 Files 클래스
•
Files 클래스는 정적 메소드로 구성되어 있기 때문에 File 클래스처럼 객체를 생성할 필요가 없다.
•
Files의 정적 메소드는 운영체제 파일 시스템에게 파일 작업을 수행하도록 위임하여 동작한다.
package com.file;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileExample2 {
public static void main(String[] args) throws IOException {
String fileName = "profile.txt"; // 프사
String dirPathStr = "/Users/haminsung/Desktop/test/java/upload";
String filePathStr = "/Users/haminsung/Desktop/test/java/upload/" + fileName;
Path dirPath = Paths.get(dirPathStr);
Path filePath = Paths.get(filePathStr);
if (!Files.exists(dirPath)) {
Files.createDirectories(dirPath);
System.out.println("디렉토리가 없어서... 생성합니다.");
BufferedWriter bw = new BufferedWriter(new FileWriter(filePathStr));
bw.write("GoodBye 최인규의 프로필 사진");
bw.flush();
bw.close();
} else {
System.out.println("이미 존재하는 디렉토리");
}
if (!Files.exists(filePath)) {
Files.createFile(filePath);
System.out.println("새로운 파일 생성 완료");
} else {
System.out.println("파일이 이미 존재");
}
}
}
Java
복사