람다
람다식(Lambda Expression)은 함수형 프로그래밍 기법을 지원하는 자바의 문법요소이다.
메서드를 하나의 ‘식(expression)’으로 표현한 것으로, 코드를 매우 간결하면서 명확하게 표현할 수 있다는 큰 장점이 있다.
람다함수를 종종 이름이 없는 함수, 즉 익명 함수(anonymous function)라 부르기도 한다.
int sum(int num1, int num2) { // 기존방식
return num1 + num2;
}
(int num1, int num2) -> { // 반환타입과 메서드명 제거 + 화살표 추가
return num1 + num2;
}
(int num1, int num2) -> { // return문과 세미콜론(;)생략
num1 + num2
}
(int num1, int num2) -> num1 + num2 // 중괄호 생략
(num1, num2) -> num1 + num2 // 매개변수타입 생략
람다식에서는 기본적으로 반환타입과 이름을 생략할 수 있다.
또한 반환값이 있는 메서드의 경우에는 return문과 문장 뒤에 오는 세미콜론(;)을 생략할 수 있다.
메서드 바디에 문장이 실행문이 하나만 존재할 때 우리는 중괄호를 생략할 수 있다.
매개변수 타입을 쉽게 유추할 수 있는 경우에는 매개변수의 타입을 생략할 수 있다.
함수형 인터페이스
자바에서 함수는 반드시 클래스 안에서 정의되어야 하기 때문에 메서드가 독립적으로 있을 수 없고 반드시 클래스 객체를 먼저 생성한 후 생성한 객체로 메서드를 호출해야한다.
이런 맥락에서 지금까지 우리가 메서드와 동일시 여겼던 람다식 또한 사실은 객체이다. 더 정확히는 이름이 없기 때문에 익명 클래스라 할 수 있다.
// sum 메서드 람다식
(num1, num2) -> num1 + num2
// 람다식을 객체로 표현
new Object() {
int sum(int num1, int num2) {
return num1 + num1;
}
}
위의 람다식으로 표현한 sum 메서드는 사실 아래와 같은 익명 클래스이다. 익명 클래스란 객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성하고, 단 한번만 사용되는 일회용 클래스이다.
만약에 람다식이 객체라 한다면 이 객체에 접근하고 사용하기 위한 참조변수가 필요하다.
그런데 기존에 객체를 생성할 때 만들었던 Object 클래스에는 sum 라는 메서드가 없기 때문에, Object 타입의 참조변수에 담는다고 하더라도 sum 메서드를 사용할 수 없다.
이 같은 문제를 해결하기 위해 사용하는 자바의 문법 요소가 바로 자바의 함수형 인터페이스(Functional Interface)라 할 수 있다.
자바에서 함수형 프로그래밍을 하기 위한 새로운 문법 요소를 도입하는 대신, 기존의 인터페이스 문법을 활용하여 람다식을 다루는 것이라 할 수 있다. 이것이 가능한 이유는 람다식도 결국 하나의 객체이기 때문에 인터페이스에 정의된 추상메서드를 구현할 수 있기 때문이다.
메서드 레퍼런스
메서드 참조는 람다식에서 불필요한 매개변수를 제거할 때 주로 사용한다.
(left, right) -> Math.max(left, right);
// 클래스이름::메서드이름
Math :: max; // 메서드 참조
스트림(Stream)
스트림(Stream)은 배열, 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자이다.
스트림을 사용하면 List, Set, Map, 배열 등 다양한 데이터 소스로부터 스트림을 만들 수 있고, 이를 표준화된 방법으로 다룰 수 있다.
스트림의 특징
1. 선언형으로 데이터 소스를 처리한다.
스트림을 이용하면, 선언형으로 데이터 소스를 처리할 수 있다.
선언형 프로그래밍이란 “어떻게" 수행하는지보다는 “무엇을” 수행하는 지에 관심을 두는 프로그래밍 패러다임이다.
명령형 방식에서는 하나하나의 절차를 따라가야만 코드를 이해할 수 있지만, 선언형 방식으로 코드를 작성하면 내부 동작 원리를 모르더라도 코드가 무슨 일을 하는지 이해할 수 있다. 즉, “어떻게"의 영역은 추상화되어 있다.
import java.util.List;
public class ImperativeProgrammingExample {
public static void main(String[] args){
// List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
//for문을 사용
int sum = 0;
for(int number : numbers){
if(number > 4 && (number % 2 == 0)){
sum += number;
}
}
System.out.println("# 명령형 프로그래밍 : " + sum);
}
}
-------------------------------------------------------------
//Stream을 사용해서 변경
int sum =
numbers.stream()
.filter(number -> number > 4 && (number % 2 == 0))
.mapToInt(number -> number)
.sum();
System.out.println("# 선언형 프로그래밍: " + sum);
}
}
2. 람다식으로 요소 처리 코드를 제공한다.
Stream이 제공하는 대부분의 요소 처리 메서드는 함수형 인터페이스 매개타입을 가지기 때문에 람다식 또는 메서드 참조를 이용해서 요소 처리 내용을 매개값으로 전달할 수 있다.
//Student.java
public class Student {
private String name;
private int score;
public Student(String name, int score){
this.name = name;
this.score = score;
}
public String getName(){
return name;
}
public int getScore(){
return score;
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamLambdaExample {
public static void main(String[] args) throws Exception {
List<Student> list = Arrays.asList(
new Student("상원윤", 95),
new Student("김이박", 92)
);
Stream<Student> stream = list.stream();
stream.forEach( s -> {
String name = s.getName();
int score = s.getScore();
System.out.println(name+ " - " +score);
});
}
}
/*
상원윤 - 95
김이박 - 92
*/
3. 내부 반복자를 사용하므로 병렬 처리가 쉽다.
외부반복자(external iterator)란 개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드 패턴을 말합니다. index를 사용하는 for문, Iterator를 이용하는 while문은 모두 외부 반복자를 이용하는 형태이다.
반면에 내부 반복자(internal iterator)는 컬렉션 내부에서 요소들을 반복시키고 개발자는 요소당 처리해야할 코드만 제공하는 코드 패턴을 이야기한다.

내부 반복자의 장점은 컬렉션 내부에서 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맡겨두고, 개발자는 요소 처리 코드에만 집중할 수 있다는 점이다.
내부 반복자는 요소들의 반복 순서를 변경하거나 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있게 도와주기 때문에 하나씩 처리하는 순차적 외부 반복자보다 효율적으로 요소를 반복시킬 수 있다. (병렬 스트림을 사용하기 위해서는 스트림의 parallel()메서드를 사용하면 된다.)
Iterator는 컬렉션의 요소를 가져오는 것에서부터 처리하는 것까지 모두 개발자가 작성해야 하지만 스트림은 람다식으로 요소 처리 내용만 전달할 뿐, 반복은 컬렉션 내부에서 일어난다.
4. 중간 연산과 최종 연산을 할 수 있다.
스트림은 컬렉션의 요소에 대해 중간 연산과 최종 연산을 수행할 수 있는데, 중간 연산에서는 매핑, 필터링, 정렬 등을 수행하고 최종 연산에서는 반복, 카운팅, 평균, 총합 등의 집계를 수행할 수 있다.
예를 들어 학생 객체를 요소로 가지는 컬렉션이 있다고 가정하면, 중간 연산에서는 학생의 점수를 뽑아내고, 최종 연산에서는 점수의 평균값을 산출할 수 있다.
파이프라인
파이프라인은 여러개의 스트림이 연결되어 있는 구조를 의미한다. 스트림은 데이터의 필터링, 매핑, 정렬, 그루핑 등의 중간 연산과 합계, 평균, 카운팅, 최대 / 최소값 등의 최종 연산을 파이프라인(pipelines)으로 해결한다. 파이프라인에서 최종 연산을 제외하고는 모두 중간 연산 스트림이다.

Stream 인터페이스에는 필터링, 매핑, 정렬 등의 많은 중간 연산 메소드가 있다. 이 메소드들은 중간 연산된 스트림을 리턴한다. 그리고 이 스트림에서 다시 중간 연산 메소드를 호출해서 파이프라인을 형성한다.
중간 스트림이 생성될 때 요소들이 바로 중간 연산(필터링, 매핑, 정렬)되는 것이 아니라 최종 연산이 시작되기 전까지는 지연된다. 최종 연산이 시작되면 비로소 컬렉션의 요소가 하나씩 중간 스트림에서 연산되고 최종 연산까지 오게 된다.
Stream<Member> maleFemaleStream = list.stream();
Stream<Member> maleStream = maleFemaleSTream.filter(m -> m.getGender() == Member.MALE);
IntStream ageStream = maleStream.mapToInt(Member::getAge);
OptionalDouble opd = ageStream.average();
double ageAve = opd.getAsDouble();
//위 코드에서 로컬 변수를 생략하고 연결하면 다음과 같은 형태의 파이프라인 코드만 남음
double ageAve = list.stream() //오리지널 스트림
.filter(m-> m.getGender() == Member.MALE) //중간 연산 스트림
.mapToInt(Member::getAge) //중간 연산 스트림
.average() //최종 연산
.getAsDouble();
스트림 생성, 중간 연산, 최종 연산
자바의 스트림은 데이터를 연속적으로 전달하는 통로로 이해할 수 있다.
스트림 생성
Collection 인터페이스에는 stream()이 정의되어 있기 때문에, Collection 인터페이스를 구현한 객체들(List, Set 등)은 모두 이 메서드를 이용해 스트림을 생성할 수 있다.
stream()을 사용하면 해당 Collection의 객체를 소스로 하는 Stream을 반환한다.
// List로부터 스트림을 생성
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> listStream = list.stream();
listStream.forEach(System.out::prinln); //스트림의 모든 요소를 출력.
배열의 원소들을 소스로하는 Stream을 생성하기 위해서는 Stream의 of 메서드 또는 Arrays의 stream 메서드를 사용한다.
// 배열로부터 스트림을 생성
Stream<String> stream = Stream.of("a", "b", "c"); //가변인자
Stream<String> stream = Stream.of(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"}, 0, 3); //end 범위 미포함
위와 같이 객체를 위한 Stream 외에도 int와 long 그리고 double과 같은 원시 자료형들을 사용하기 위한 특수한 종류의 Stream(IntStream, LongStream, DoubleStream)들도 사용할 수 있으며, Intstream은 range()함수를 사용하여 기존의 for문을 대체할 수 있다.
// 4이상 10미만의 숫자를 갖는 IntStream
IntStream stream = IntStream.range(4, 10);
스트림은 주로 컬렉션과 배열에서 얻지만, 다음과 같은 소스로부터 스트림 구현 객체를 얻을 수도 있다.
| 리턴 타입 | 메서드(매개 변수) | 소스 |
| Stream | java.util.Collection.Stream(), java.util.Collection.parallelSream( ) | 컬렉션 |
| Stream, IntStream, LongStream, DoubleStream | Arrays.stream(T[]), Arrays.stream(int[]), Arrays.stream(long[]), Arrays.stream(double[]), Stream.of(T[]), IntStream.of(int[]) LongStream.of(long[]), DoubleStream.of(double[]) | 배열 |
| IntStream | IntStream.range(int, int), IntStream.rangeClosed(int, int) | int 범위 |
| LongStream | LongStream.range(long, long), LongStream.rangeClosed(long, long) | long 범위 |
스트림을 사용할 때 주의할 점
- 스트림은 데이터 소스로부터 데이터를 읽기만 할 뿐 변경하지 않는다(Read-only).
- 스트림은 일회용입니다. 한 번 사용하면 닫히므로, 필요하다면 새로운 스트림을 만들어야 한다.
중간 연산

중간 연산은 연산 결과를 스트림으로 반환하기 때문에, 연속해서 여러 번 수행할 수 있다.
스트림의 주요 중간 연산 메서드
필터링(filter(), distinct())
distinct() : Stream의 요소들에 중복된 데이터가 존재하는 경우, 중복을 제거하기 위해 사용한다.
filter() : Stream에서 조건에 맞는 데이터만을 정제하여 더 작은 컬렉션을 만들어낸다. filter() 메서드에는 매개값으로 조건(Predicate)이 주어지고, 조건이 참이 되는 요소만 필터링한다.
import java.util.Arrays;
import java.util.List;
public class FilteringExample {
public static void main(String[] args) throws Exception {
List<String> names = Arrays.asList("김코딩", "이자바", "김스트", "김코딩");
names.stream()
.distinct() //중복제거
.forEach(n -> System.out.println(n));
System.out.println();
names.stream()
.filter(n -> n.startsWith("김")) //필터링
.forEach(n -> System.out.println(n));
System.out.println();
names.stream()
.distinct() //중복제거
.filter(n -> n.startsWith("김")) //필터링
.forEach(n -> System.out.println(n));
}
}
/*
김코딩
이자바
김스트
김코딩
김스트
김코딩
김코딩
김스트
*/
매핑(map())
map() : 기존의 Stream 요소들을 대체하는 요소로 구성된 새로운 Stream을 형성하는 연산이다.
저장된 값을 특정한 형태로 변환하는데 주로 사용되며, Java에서는 map 함수의 인자로 함수형 인터페이스 function을 받고 있다.
map() 메서드는 작업을 하다 보면 일반적인 Stream 객체를 원시 Stream으로 바꾸거나 그 반대로 하는 작업이 필요한 경우에 쓰입니다. 반대로 원시 객체는 mapToObject를 통해 일반적인 Stream 객체로 바꿀 수 있다.
flatMap(): flatMap은 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림을 리턴한다.
flatMap()과 map()의 차이점은, map()은 스트림의 스트림을 반환하는 반면, flatMap()은 스트림을 반환한다( 전자의 리턴 타입이 Stream<Stream>이라면, 후자의 리턴 타입은 Stream )
정렬(sorted())
Stream의 요소들을 정렬하기 위해서는 sorted를 사용해야 하며, 파라미터로 Comparator를 넘길 수도 있다. Comparator 인자 없이 호출할 경우에는 오름차순으로 정렬이 되며, 내림차순으로 정렬하기 위해서는 Comparator의 reverseOrder를 이용한다.
List<String> list = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift");
list.stream()
.sorted()
.forEach(n -> System.out.println(n));
System.out.println();
/*
Go, Groovy, Java, Python, Scala, Swift
*/
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(n -> System.out.println(n));
/*
Swift, Scala, Python, Java, Groovy, Go
*/
연산 결과 확인(peek())
peek(), forEach()는 요소를 하나씩 돌면서 출력한다는 기능에서는 동일하지만, 동작 방식은 다르다.
peek은 중간 연산 메서드이고, forEach는 최종 연산 메서드이다. forEach는 스트림의 요소를 소모하므로 한 번만 호출할 수 있지만(재호출하려면 새로운 스트림을 생성해야 함), peek은 중간 연산이므로 하나의 스트림에 여러 번 사용할 수 있다.
peek()은 주로 연산 중간에 결과를 확인하여 디버깅하고자 할 때 사용한다.
intStream
.filter(a -> a%2 ==0)
.peek(n-> System.out.println(n))
.sum();
최종 연산
최종 연산은 연산 결과가 스트림이 아니므로, 한 번만 연산이 가능하다.
연산 결과 확인(forEach())
forEach는 최종 연산 메서드이기 때문에 파이프라인 마지막에서 요소를 하나씩 연산한다.
forEach값을 출력할 때도 사용하지만, 이메일 발송, 스케줄링 등 리턴 값이 없는 작업에서도 많이 사용한다.
intStream
.filter(a -> a%2 ==0)
.forEach(n -> System.out.println(n));
매칭(match())
match() 메서드는 함수형 인터페이스 Predicate를 받아서 Stream의 요소들이 특정한 조건을 충족하는지 검사하고, 검사 결과를 boolean으로 반환한다. match() 메서드에는 크게 다음 3 가지가 있다.
- allMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 조사
- anyMatch() : 최소한 한 개의 요소가 매개값으로 주어진 Predicate의 조건을 만족하는지 조사
- noneMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하지 않는지 조사
기본 집계(sum(), count(), average(), max(), min())
집계는 최종 연산 기능으로 요소들을 카운팅, 합계, 평균값, 최대값, 최소값 등으로 연산하여 하나의 값으로 산출하는 것을 의미한다.
import java.util.Arrays;
public class AggregateExample {
public static void main(String[] args) throws Exception {
int[] intArr = {1,2,3,4,5};
long count = Arrays.stream(intArr).count();
System.out.println("intArr의 전체 요소 개수 " + count);
long sum = Arrays.stream(intArr).sum();
System.out.println("intArr의 전체 요소 합 " + sum);
double avg = Arrays.stream(intArr).average().getAsDouble();
System.out.println("전체 요소의 평균값 " + avg);
int max = Arrays.stream(intArr).max().getAsInt();
System.out.println("최대값 " + max);
int min = Arrays.stream(intArr).min().getAsInt();
System.out.println("최소값 " + min);
int first = Arrays.stream(intArr).findFirst().getAsInt();
System.out.println("배열의 첫번째 요소 " + first);
}
}
/*
intArr의 전체 요소 개수 5
intArr의 전체 요소 합 15
전체 요소의 평균값 3.0
최대값 5
최소값 1
배열의 첫번째 요소 1
*/
reduce()
reduce는 누적하여 하나로 응축(reduce)하는 방식으로 동작한다. 앞의 두 요소의 연산 결과를 바탕으로 다음 요소와 연산한다.
educe 메서드는 최대 3개의 매개변수를 받을 수 있다.
- 누산기 Accumulator: 각 요소를 계산한 중간 결과를 생성하기 위해 사용
- Identity: 계산을 수행하기 위한 초기값
- 결합기 Combiner: 병렬 스트림(Parlallel Stream)에서 나누어 계산된 결과를 하나로 합치기 위한 로직
import java.util.Arrays;
public class ReduceExample {
public static void main(String[] args) throws Exception {
int[] intArr = {1,2,3,4,5};
long sum = Arrays.stream(intArr).sum();
System.out.println("intArr의 전체 요소 합 " + sum);
int sum1 = Arrays.stream(intArr)
.map(el -> el*2)
.reduce((a,b) -> a+b)
.getAsInt();
System.out.println("초기값 없는 reduce " + sum1);
int sum2= Arrays.stream(intArr)
.map(el -> el*2)
.reduce(0, (a,b) -> a+b);
System.out.println("초기값 존재하는 reduce " + sum2)
}
}
/*
intArr의 전체 요소 합 15
초기값 없는 reduce 30
초기값 존재하는 reduce 30
*/
초기값이 있는 reduce는 초기값과 스트림의 첫 번째 요소로 첫 연산을 수행한다. 초기값이 없는 reduce는 스트림의 첫 번째 요소와 두 번째 요소로 첫 연산을 수행한다.
collect()
Stream의 요소들을 List나 Set, Map, 등 다른 종류의 결과로 수집하고 싶은 경우에는 collect 메서드를 이용할 수 있다.
collect 메서드는 어떻게 Stream의 요소들을 수집할 것인가를 정의한 Collector 타입을 인자로 받는다. 이는 Collector 인터페이스를 구현한 클래스이다.
Optional<T>
Optional은 NullPointerException(NPE), 즉 null 값으로 인해 에러가 발생하는 현상을 객체 차원에서 효율적으로 방지하고자 도입되었습니다.
Optional 클래스는 모든 타입의 객체를 담을 수 있는 래퍼(Wrapper) 클래스이다.
ptional 객체를 생성하려면 of() 또는 ofNullable()을 사용합니다. 참조변수의 값이 null일 가능성이 있다면, ofNullable()을 사용한다.
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
List<String> languages = Arrays.asList(
"Ruby", "Python", "Java", "Go", "Kotlin");
Optional<List<String>> listOptional = Optional.of(languages);
int size = listOptional
.map(List::size)
.orElse(0); // null이면 0을 출력하라
System.out.println(size);
}
}
InputStream, OutputStream
자바에서는 입출력을 다루기 위한 InputStream, OutputStream을 제공한다. 스트림은 단방향으로만 데이터를 전송할 수 있기에, 입력과 출력을 동시에 처리하기 위해서는 각각의 스트림이 필요하다.
입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉜다. 예를 들면, File을 다룰 때는 FileInputStream / FileOutputStream을 사용하고, 프로세스를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다.
FileInputStream
터미널에 아래 명령어를 입력하면 GoodMoring이라는 문자열이 입력된 hello.txt 파일이 생성된다.
echo GoodMorning >> hello.txt
아래 코드를 실행하면
import java.io.FileInputStream;
public class FileInputStreamExample {
public static void main(String args[])
{
try {
FileInputStream fileInput = new FileInputStream("hello.txt");
int i = 0;
while ((i = fileInput.read()) != -1) { //fileInput.read()의 리턴값을 i에 저장한 후, 값이 -1인지 확인합니다.
System.out.print((char)i);
}
fileInput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}

hello.txt 파일에 있던 문자열이 출력된다.
BufferedInputStream이라는 보조 스트림을 사용하면 성능이 향상되기 때문에, 대부분의 경우 이를 사용한다.버퍼란 바이트 배열로서, 여러 바이트를 저장하여 한 번에 많은 양의 데이터를 입출력할 수 있도록 도와주는 임시 저장 공간이라고 이해하면 된다.
import java.io.FileInputStream;
import java.io.BufferedInputStream;
public class FileInputStreamExample {
public static void main(String args[])
{
try {
FileInputStream fileInput = new FileInputStream("hello.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
int i = 0;
while ((i = bufferedInput.read()) != -1) {
System.out.print((char)i);
}
fileInput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}
FileOutputStream
import java.io.FileOutputStream;
public class FileOutputStreamExample {
public static void main(String args[]) {
try {
FileOutputStream fileOutput = new FileOutputStream("sangwon.txt");
String word = "code";
byte b[] = word.getBytes();
fileOutput.write(b);
fileOutput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}
위 코드를 실행하면, 같은 디렉토리 내에 code라는 문자열이 입력된 sangwon.txt 파일이 생성됨을 확인할 수 있다.
FileReader / FileWriter
File 입출력 스트림은, 바이트 기반 스트림이다. 입출력 단위가 1byte라는 뜻이다. 하지만 Java에서 char 타입은 2byte(자바 기본 유닛 참고)입니다. 이를 해소하기 위해 자바에서는 문자 기반 스트림을 제공한다.
문자 기반 스트림은 문자 데이터를 다룰 때 사용한다. 문자 기반 스트림과 그 하위 클래스는 여러 종류의 인코딩(encoding)과 자바에서 사용하는 유니코드(UTF-16)간의 변환을 자동으로 처리한다.
FileReader는 인코딩을 유니코드로 변환하고, FileWriter는 유니코드를 인코딩으로 변환한다.
FileReader
public class FileReaderExample {
public static void main(String args[]) {
try {
String fileName = "hello.txt";
FileReader file = new FileReader(fileName);
int data = 0;
while((data=file.read()) != -1) {
System.out.print((char)data);
}
file.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
hello.txt파일에 안녕하세요 라는 한글 문자열을 입력하고 위 코드를 실행시킨다.

FileWriter
public class FileWriterExample {
public static void main(String args[]) {
try {
String fileName = "hello.txt";
FileWriter writer = new FileWriter(fileName);
String str = "반가워!";
writer.write(str);
writer.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
앞서 만든 hello.txt파일에 “반가워!”라는 문자열을 입력하는 예제다.
File
자바에서는 File 클래스로 파일과 디렉토리에 접근할 수 있다.
'Java' 카테고리의 다른 글
| 객체 지향 설계의 SOLID 원칙 (0) | 2024.06.20 |
|---|---|
| Java 스레드, JVM (0) | 2022.09.16 |
| Java컬렉션 (0) | 2022.09.14 |
| Java기초 사칙연산 계산기 만들기 (0) | 2022.09.09 |
| Java 다향성, 추상화, 인터페이스 (0) | 2022.09.07 |