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
복사