Backend
home

2024. 7. 25

스트림 - 요소를 하나씩 처리

•
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)은 단방향으로 동작한다.
•
프로그램 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 된다.
•
프로그램에서 다른 프로그램과 데이터를 교환하기 위해서는 양쪽 모두 입력 스트림과 출력 스트림이 필요하다.
•
스트림 종류
◦
바이트 스트림: 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용한다.
◦
문자 스트림: 문자만 입출력할 때 사용
◦
데이터 입출력 관련된 라이브러리: java.io 패키지에서 제공
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
복사