데이터를 담는 저장소 X
원본 데이터를 변경하지 않고 처리 가능
연속적이고 선언적인 데이터 처리 가능
파이프라인처럼 연결된 연산을 수행함
데이터 → 중간연산 → 중간연산 → ... → 최종연산
List → filter → map → collect
스트림은 데이터를 한 줄씩 처리하며, 중간 연산은 최종 연산이 호출되어야 실행된다. (지연 평가)
스트림은 중간 연산과 최종 연산으로 나뉜다.
중간 연산 (결과가 스트림)
filter(Predicate): 조건에 맞는 요소만 추출
map(Function): 요소 변환
sorted(): 정렬
distinct(): 중복 제거
limit(n), skip(n): 자르기/건너뛰기
최종 연산 (스트림 종료)
forEach(Consumer): 요소 반복 처리
collect(Collectors): 결과 수집
count(), sum(), max(), min()등
anyMatch(), allMatch(), noneMatch()등
package lesson08;
import java.util.Arrays;
import java.util.List;
public class Ex01_Main {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "orange", "apple");
System.out.println(fruits);
/*
String::toUpperCase
- 메서드 참조
s -> s.toUpperCase()와 같은 람다식을 더 간단하게 표현
String 클래스의 toUpperCase() 인스턴스 메서드를 현재 스트림의 각 요소에 대해 호출하겠다는 뜻
*/
fruits.stream()
.filter(f->f.startsWith("a"))
.map(String::toUpperCase)
.distinct()
.forEach(System.out::println);
}
}
입력 스트림 (Input)
외부 → 프로그램으로 데이터 입력
InputStream, Reader
출력 스트림 (Output)
프로그램 → 외부로 데이터 출력
OutputStream, Writer
바이트 스트림
1바이트 단위로 처리 (이미지, 영상 등 이진 데이터) InputStream, OutputStream
문자 스트림
문자 단위로 처리 (텍스트 데이터)
Reader, Writer
package lesson08;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Ex02_Main {
public static void main(String[] args) {
try(
FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
){
int data;
while((data = fis.read())!=-1){
fos.write(data);
}
System.out.println("파일 복사 완료(바이트 스트림)");
}catch(IOException e){
e.printStackTrace();
}
}
}
package lesson08;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Ex03_Main {
public static void main(String[] args) {
try(
FileReader reader = new FileReader("input.txt");
FileWriter writer = new FileWriter("output2.txt")
){
int ch;
while ((ch = reader.read())!=-1){
writer.write(ch);
}
System.out.println("파일 복사 완료(문자 스트림)");
}catch (IOException e){
e.printStackTrace();
}
}
}
자바에서 객체를 바이트 형태로 변환하여 파일에 저장하거나 네트워크를 통해 전송할 수 있도록 만드는 과정.
-> 직렬화된 데이터는 사람이 읽을 수 없는 이진 형식으로 저장된다.
-> 보통 .ser 확장자를 가진 파일에 저장한다.
-> 프로그램이 종료되어도 객체의 상태를 저장하거나, 다른 시스템 간에 객체를 전달할 수 있다.
직렬화를 위해 해당 클래스가 Serializable 인터페이스를 구현해야 한다.
직렬화할 클래스는 java.io.Serializable 인터페이스를 구현해야 한다.
-> java.io.Serializable 인터페이스 : 마커 인터페이스, 구현할 메서드 없음.
클래스의 필드는 모두 직렬화가 가능한 타입이어야 한다.
-> 직렬화되지 말아야 하는 필드는 transient 키워드 사용
역직렬화(Deserialization) : 바이트 데이터를 다시 객체로 복원하는 과정
package lesson08;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Student implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "학생 이름: " + name + ", 나이: " + age;
}
}
public class Ex04_Main {
public static void main(String[] args) {
Student s = new Student("김사과", 20);
try(
FileOutputStream fos = new FileOutputStream("student.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
){
oos.writeObject(s); // 직렬화
System.out.println("객체를 파일에 저장했습니다.");
}catch (Exception e){
e.printStackTrace();
}
}
}
package lesson08;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Ex05_Main {
public static void main(String[] args) {
try(
FileInputStream fis = new FileInputStream("student.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
){
Student s = (Student) ois.readObject(); // 역직렬화
System.out.println("복원된 객체: " + s);
}catch (Exception e){
e.printStackTrace();
}
}
}
serialVersionUID
private static final long serialVersionUID = 1L;
자바는 직렬화된 객체를 읽어올 때, 원래 클래스와 구조가 같아야 역직렬화가 가능하다. (클래스 구조 바뀌면 문제 생김.)
// 저장 당시
class Student implements Serializable {
String name;
}
// 변경 후
class Student implements Serializable {
String name;
int age; // 필드 추가
}
이때 serialVersionUID가 다르면 역직렬화 시 오류가 발생한다. (InvalidClassException 예외 발생)
// Student.java
import java.io.Serializable;
public class Student implements Serializable {
String name;
int age; // 새 필드 추가
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "이름: " + name + ", 나이: " + age;
}
}
// 복원 코드
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.ser"));
Student s2 = (Student) ois.readObject(); // ❌ InvalidClassException 발생