0. 열거형(Enum)
개요
학습 목표
- Enum의 개념 이해
- Enum의 등장 배경과 장점
- Enum의 문법 요소
열거형(enum)
enum Month{JAN, ...}
enum Week{MON,...}
- Enum의 장점
- 중복 상수명, 타입 안정성 피할 수 있다
- 코드 가독성과 switch문 사용 가능
- switch문은 사용자 정의 타입은 조건으로 받지 않는다
- enum Month {JAN, FEB, MAR, APR} //기존 방식으로 하면 오류 발생 class enumExample{ public static void main(String[] args){ Month month = Month.JAN; switch(month){ case JAN: ... case FEB: ... case MAR: ... case APR: ... } } }
열거형의 사용
- 열거형 선언
- enum 열거형 이름 { 상수명, …}
- 열거형 이름은 관례적으로 대문자로 표현
- 열거형 안에 열거형 객체들 존재
- 상수값을 지정하지 않아도 0부터 할당
enum Month {JAN, FEB, MAR, APR}
class enumExample{
public static void main(String[] args){
Month month = Month.JAN;
switch(month){
case JAN: System.out.println("JAN"); //JAN 출력
case FEB: System.out.println("FEB");
case MAR: System.out.println("MAR");
case APR: System.out.println("APR");
}
Month[] monthAll = Month.values(); // 모든 enum 객체 배열로 저장
for(Month mon : monthAll)
System.out.println("%s, %d", mon.name(), mon.ordinal());
//모든 객체 문자열, 상수값 출력
System.out.println(valueof("JAN")); // JAN의 열거 객체 출력
}
}
- 열거형 메서드
- java.lang.Enum에 정의된 메서드
- name() : 열거 객체가 가지는 문자열 반환
- ordinal() : 열거 객체 순번 반환
- compareTo() : 주어진 매개 값과 비교해 순번 차이 반환
- valueOf() : 주어진 문자열의 열거 객체 반환
- values() : 모든 열거 객체 배열로 반환
1. 애너테이션(Annotation)
개요
학습 목표
- 애너테이션 개념
- 표준 애너테이션 VS 메타 애너테이션
- 사용자 정의 애너테이션
애너테이션의 용도와 종류
애너테이션의 용도
- 정보 전달
- 역할
- 컴파일러에게 문법 체크 정보 제공
- 빌드할 때 코드 자동 생성 정보 제공
- 런타임에 특정 기능 실행 정보 제공
- 타깃 이외의 다른 프로그램에서는 유효하지 않음
- 종류
- 표준 애너테이션 : 자바에서 기본 제공
- @Override : 메서드 오버 라이딩
- @Deprecated : 앞으로 사용하지 않을 대상
- @SuppressWarnings : 컴파일러가 경고 메시지 표시 X
- @FunctionalInterface : 함수형 인터페이스
- 메타 애너테이션 : 애너테이션을 정의하는 데 사용
- @Target : 적용 대상
- @Documented : javadoc으로 작성된 문서에 애너테이션 정보 포함
- @Inherited : 하위 클래스에 상속
- @Retention : 애너테이션 유지 기간
- @Repeatable : 애너테이션 반복 적용
- 사용자 정의 애너테이션 : 사용자가 직접 정의
표준 애너테이션
@Override
- 역할
- 상위 클래스의 메서드를 오버 라이딩한다는 것을 컴파일러에게 알림
- 특징
- 목적
- 오버라이딩 실수로 잘못 작성했을 때 알림을 받을 수 있도록..
@Deprecated
- 역할
- 새로운 것으로 대체하였으니 기존의 것을 사용하지 않는 것을 권장시키는 역할
- 특징
- 필드나 메서드 앞에 붙일 수 있음
- @Deprecated가 붙은 멤버를 사용할 때 오류 발생
@SuppressWarnings
- 역할
- @SuppressWarnings(”example”)
- all : 모든 경고 억제
- deprecation : Deprecated 메서드를 사용했을 때 나오는 경고 억제
- fallthrough : switch문에 break 없을 때 나는 경고 억제
- finally : finally 관련 경고 억제
- null : null 관련 경고 억제
- unchecked : 검증되지 않은 연산자 경고 억제
- unused : 사용하지 않은 코드 관련 경고 억제
- {}로 여러 개 사용 가능
@FunctionalInterface
- 역할
- 함수형 인터페이스 선언이 잘 되었는지 확인
- 함수형 인터페이스는 단 하나의 추상 메서드만 가지는 인터페이스
메타 애너테이션
@Target
- 역할
- 애너테이션 적용 대상 지정
- ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE(클래스, 인터페이스, 열거형), TYPE_PARAMETER, TYPE_USE(타입을 사용되는 모든 대상)
- 활용
import static java.lang.annotation.ElementType.*;
//ElementType.TYPE 대신 간단하게 TYPE, FIELD 처럼 작성 가능
@Target({FIELD, TYPE, TYPE_USE}) //FIELD, TYPE 적용
public @interface AnnotationExam { } // AnnotationExam 사용자 정의
@AnnotationExam // TYPE에 적용
class Main {
@AnnotationExam // FIELD에 적용
double num;
}
@Documented
- 역할
- javadoc으로 작성한 문서에 애너테이션에 대한 정보 포함
- 특징
- @Override, @SuppressWarnings를 제외한 모든 애너테이션이 @Documented 적용
- 활용
@Documented
@Target(ElementType.TYPE)
public @interface AnnotationExam { ... }
@Inherited
- 역할
- 하위 클래스가 애너테이션을 상속받게 하는 역할
- 상위 클래스에 @Inherited를 붙이면 하위 클래스도 동일하게 애너테이션 적용
- 활용
@Inherited
@interface Example{} //Inherited가 적용된 사용자 정의 애너테이션
@Example
class A {} //하위 클래스도 적용
class B extends A{ ... }
@Retention
- 역할
- RetentionPolicy
- SOURCE : 소스 파일에 존재
- CLASS : 클래스 파일에 존재, 기본값, 실행 시 사용불가
- RUNTIME : 클래스 파일에 존재, 실행 시 사용 가능
- 활용
- @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override(){ ... } // method에 적용하고 실행 시 사용 불가한 사용자 정의 애너테이션
@Repeatable
- 역할
- 활용
- @Repeatable(colors.class) @interface color{ String value(); } @interface colors{ color[] value(); } @color("red") @color("green") @color("blue") class RGB{ ... }
사용자 정의 애너테이션
2. 람다(Lambada)
개요
학습 목표
- 람다식
- 함수형 인터페이스를 통한 람다
- 람다식을 메서드 참조 방식으로 변환
람다식의 기본 문법
기존 방식과 람다식의 차이
void call(){
System.out.println("call!!!");
} // 기존 방식
() -> System.out.println("call!!!") //람다식
- 변환형과 메서드 이름을 생략 가능 (익명 함수라고도 불림)
메서드 → 람다식
int multi(int a, int b){
return a*b;
}
(a,b)->a*b
- 반환형 타입과 이름을 제거하고 return과 세미콜론 생략 가능
- 실행문 한 줄이면 중괄호 생략 가능
- 매개변수 타입은 유추가 가능한 경우 생략 가능
함수형 인터페이스
- 함수형 인터페이스 사용 이유
- 람다식은 익명 클래스(참조 변수 선언 없이 객체 정의와 생성을 동시에 하는 일회성 클래스)
- Object 클래스로 생성해서 만들면 그 안의 메서드를 사용 불가
- 이에 따라 함수형 인터페이스를 사용
- 함수형 인터페이스 특징
- 단 하나의 추상 메서드만 선언
- 매개변수, 리턴 값에 따른 함수형 인터페이스 예제
public Lambda {
public static void main(String[] args) {
LambdaMulti1 multi1;
multi1=()->{
String str="multi1";
System.out.println(str);
}
multi1.multi(); // multi1 출력(매개변수, 리턴값 없는 경우)
LambdaMulti2 multi2;
multi2=(int a, int b)->{
String str="multi2";
System.out.printf("%s : %d, %d",str,a, b);
}
multi2.multi(2,3); // multi2 : 2, 3 출력(매개변수 있는 경우)
LambdaMulti3 multi3;
multi3=(int a, int b)->{
String str="multi3";
System.out.printf("%s : %d*%d=%d",str,a, b, a*b);
}
multi3.multi(2,3); // multi3 : 2*3=6 출력(매개변수, 리턴값 있는 경우)
}
}
@FunctionalInterface
public interface LambdaMulti1{
public abstract void multi(); //매개변수, 리턴값이 없는 람다식
}
@FunctionalInterface
public interface LambdaMulti2{
public abstract void multi(int a, int b); //매개변수가 있는 람다식
}
@FunctionalInterface
public interface LambdaMulti3{
public abstract int multi(int a, int b); //매개변수,리턴값 있는 람다식
}
- 자바에서 기본 제공하는 함수형 인터페이스 존재
함수형 인터페이스 종류
- java.util.function 패키지의 함수형 인터페이스
함수형 인터페이스 |
메서드 명 |
Runnable |
run() |
Supplier |
R get() |
Consumer |
accept(T) |
Function<T,R> |
R apply(T) |
메서드 레퍼런스
메서드 레퍼런스
- 람다식을 더 간단하게 사용
- 클래스 이름 :: 메서드 이름
import java.util.function.IntBinaryOperator;
(a,b)-> Math.max(a,b); //람다식
IntBinaryOperator op = Math :: max; //메서드 참조
정적 메서드와 인스턴스 메서드
import java.util.function.IntBinaryOperator;
public class Example{
public static int stMethod(int a, int b){
return a-b;
}
public int instMethod(int a, int b){
return a/b;
}
}
public class ReferenceExam{
public static void main(String[] args){
IntBinaryOperator op;
op = Example :: stMethod;
System.out.println(op.applyAsInt(6,2)) // 정적메서드 참조(출력: 4)
Example exam=new Example();
op=exam :: instMethod;
System.out.println(op.applyAsInt(6,2)) // 인스턴스 메서드 참조(출력 : 3)
}
}
생성자 참조
- 람다식 생성자 참조 방식
- (a,b) → { return new 클래스명(a,b);};
- 객체를 생성하고 리턴하여 람다식으로 생성자 참조 가능
- 생성자 참조
- 클래스 :: new
- 함수형 인터페이스에서 추상 메서드와 동일한 매개변수 타입과 개수를 찾아 생성자 실행
- 활용
import java.util.function.BiFunction;
import java.util.function.Function;
class User{
private String id;
private String pw;
User(int id){
this.id=id;
}
User(int id, pw){
this.id=id;
this.pw=pw;
}
public String getId(){
return id;
}
public String setId(String id){
this.id=id;
}
public String getPw(){
return pw;
}
public String setId(String pw){
this.pw=pw;
}
}
class Example{
public static void main(String[] args){
Function<String, User> f1= User::new;
User user1=f1.apply("kdjf");
BiFunction<String, String, User> f2=User::new;
User user2=f2.apply("kdjf", "1234");
- Function 함수형 인터페이스에 apply라는 메서드 존재(내용이 없는 메서드)
- interface Function<Input, Output>{ public abstract Output apply (Input); } interface Function<Input1, Input2, Output>{ public abstract Output apply (Input1, Input2); }
3. 스트림(Stream)
개요
스트림
- 하나씩 참조하여 람다식으로 처리할 수 있는 반복자
학습 목표
- 스트림 특성, 목적
- 컬렉션, 배열의 스트림
- 스트림 주요 메서드
스트림 특징
선언형으로 데이터 소스 처리
- 명령형
- 선언형
- 무엇을 수행할지, 코드가 무슨 일을 할지를 알 수 있음
- 활용
List<Integer> nums = List.of(1,2,3,4,5,6);
int result = nums.stream()
.filter(num -> num % 2==1)
.mapToInt(num -> num)
.sum(); // 홀수들의 합을 stream으로 구현
람다식으로 요소 처리 코드 제공
- 대부분의 요소 처리
- 함수형 인터페이스 매개 타입을 가지기 때문에 람다식이나 메서드 참조로 매개 값 전달
내부 반복자 사용으로 병렬 처리 용이
- 외부 반복자
- 개발자가 코드로 직접 컬렉션 요소를 반복해서 가져오는 형식
- index를 사용하는 for문, iterator를 사용하는 while문
- 내부 반복자
- 컬렉션 내부 요소를 반복하고 요소당 처리할 코드만 제공하는 형식
- 내부 반복자 장점
- 어떻게 반복할 것 인가를 컬렉션에게 맡기고 개발자는 처리할 코드만 집중
- 멀티코어나 CPU를 최대한 활용하기 위해 병렬 작업 가능(parallel() 메서드로 가능)
중간 연산과 최종 연산 가능
파이프라인 구성(.)
리덕션(Reduction)
- 대량의 데이터를 축소하는 과정
- 리덕션의 결과물을 바로 집계하기 힘든 경우 중간 연산 필요
파이프라인
- 파이프라인
- 여러 개의 스트림이 연결되어 있는 구조
- 최종 연산을 제외하고 중간 연산 스트림
- 최종 연산 시작되면 중간 스트림에서 연산되고 최종 연산까지 진행
- Stream 인터페이스
- 필터링, 매핑, 정렬 등 많은 중간 연산 메서드 존재
- 중간 연산 스트림을 리턴하고 반복하여 파이프라인 형성
스트림 생성, 중간 연산, 최종 연산
Stream
.of(1,2,3,4,5,6) // 데이터 소스
.filter(num -> num%2==0) 중간연산
.map(num -> num*3) //중간연산
.forEach(System.out.println(num)); // 최종연산
스트림 생성
- Collection 인터페이스에 stream() 정의
- Collection 인터페이스를 구현한 객체들(List, Set) 등은 모두 스트림 생성 가능
- Stream 생성 방식
- List list = Arrays.asList("a","b","c"); Stream stream=list.stream(); // 1. stream()메서드 활용 //배열 원소를 스트림으로 생성 Stream stream2 = Stream.of(new String[]{"a","b","c"}) //2. Stream.of() Stream stream3=Arrays.stream(new String[]{"a"."b","c"},0,3) //3. Arrays.stream() //마지막 인덱스는 미포함
- Primitive type(원시 자료형)을 위한 stream(IntStream, LongStream, DoubleStream)
- IntStream intStream = IntStream.range(1, 5); //range를 활용해 첫 번째 인덱스 이상 //마지막 인덱스 미만을 요소로 갖는 스트림 생성
- 소스에 따른 Stream
- 컬렉션 : java.util.Collection.Stream(), java.util.Collection.parallelStream( )
- 배열 : Arrays.stream(T[]), Arrays.stream(int[]), Arrays.stream(long[]), Arrays.stream(double[]), Stream.of(T[]), IntStream.of(int[]) LongStream.of(long[]), DoubleStream.of(double[])
- int : IntStream.range(int, int), IntStream.rangeClosed(int, int)
- long : LongStream.range(long, long), LongStream.rangeClosed(long, long)
- Stream 사용 주의 사항
- Read only - 데이터를 읽기만 하고 수정 불가
- 1회용 - 한 번 사용하면 스트림 닫힘
중간 연산
- 필터링(filter())
- filter() : 매개 값에 조건을 넣고 참인 것들만 추출
- distinct() : 중복제거
List<Integer> list = Arrays.asList("13", "256", "3235", "4246", "5679", "13");
list.stream()
.distinct() // 중복 제거
.filter(n -> n.startsWith("1") // 조건 추출
.forEach(n->System.out.println(n)); // 13
- 매핑(map())
- map() : 기존의 stream 요소들을 대체하는 새로운 stream 생성
- mapToInt(), mapToLong(), mapToDouble() : 원시 stream으로 변환
- mapToObject() : 일반 stream 객체로 변환
- flatMap() : 모든 원소를 단일 원소 스트림으로 반환
List<String> list = Arrays.asList("Apple", "Banana");
list.stream()
.map(s->s.toLowerCase())
.forEach(s->System.out.println(s)); // apple banana 출력
Stream<String[]> example
.stream.of(new String[]{"A", "B", "C"}, new String[]{"D", "E"})
.flatMap(Arrays::stream)
.forEach(System.out::println); // A, B, C, D, E 출력
- 정렬(sorted())
- sorted() 사용해서 기본 오름차순으로 정렬
- 내림차순은 Comparator.reverseOrder()를 매개변수로 입력
- Comparable을 구현하지 않은 클래스는 Comparator.comparing()을 활용 매개변수에 어떤 것 비교할지 메서드 참조나 함수형 인터페이스로 구현
List<String> list = Arrays.asList("Apple","Melon","Banana");
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println) // Melon Banana Apple 출력
Stream<Student> streamExample
.sorted(Comparator.comparing(Student::getName))
.forEach(System.out::println); // Student 클래스에 Name을 정렬하여 출력
- 연산 결과 확인(peek())
- 요소를 하나씩 돌면서 출력
- peek() : 중간 연산 메서드(하나의 스트림에 여러 번 가능)
- forEach() : 최종 연산 메서드(한 번만 호출 가능, 재호출 하려면 새 스트림 생성 필요)
streamExample
.filter(n-> n%2==0)
.peek(n->System.out.println(n)) // 중간 연산 확인
.sum(); // 짝수 합
최종 연산
- 한 번만 호출 가능
- 연산 결과 확인(forEach())
- 마지막에 하나씩 연산
- 출력 외 리턴 값이 없는 경우에도 사용
- 매칭(match())
- 함수형 인터페이스 Predicate를 받아서 해당 조건을 만족하는지 검사하고 boolean으로 출력
- allMatch() : 모든 요소가 해당 조건을 만족하는지 출력
- anyMatch() : 하나라도 해당 조건을 만족하는 지 출력
- noneMatch() : 모든 요소가 해당 조건을 만족하지 않는지 출력
int[] arr={1,2,3,4,5,6};
boolean check1=Arrays.stream(arr).allMatch(n-> n%3==0); //3의 배수인지 확인, false
boolean check2=Arrays.stream(arr).anyMatch(n-> n%3==0); // 하나라도 3의 배수인지 확인, true
boolean check3=Arrays.stream(arr).noneMatch(n-> n%3==0); // 모두 3의 배수가 아닌지 확인, false
- 기본 집계(sum(), count(), average(), max(), min())
int[] arr={1,2,3,4,5,6};
long result1=Arrays.stream(arr).sum(); // 21 배열이기 때문에 mapToInt를 안해도 된다
// .sum은 반환형이 int, long, double
long result2=Arrays.stream(arr).count(); // 6 .count는 반환형이 long
double result3=Arrays.stream(arr).average().getAsDouble(); // 3.5 반환형이 Optional
int result4=Arrays.stream(arr).max().getAsInt(); // 6 반환형이 Optional
int result5=Arrays.stream(arr).min().getAsInt(); // 1 반환형이 Optional
int result6=Arrays.stream(arr).findFirst().getAsInt(); // 1 반환형이 Optional
//getAsInt 대신에 orElse()를 쓸수 있다
//orElse()는 Optional 객체 안에 있는 내용을 반환하거나 null이라면 인자를 반환
//orElse()의 인자는 객체로만 들어가고 그 객체가 null로 받아들이지 않아 null로 들어가면
//NullPointerException 에러가 난다
- reduce()
- 누적하여 하나로 응축하는 방식
- 앞의 두 요소와 연산하여 다음 요소를 연산
- reduce(Identity, Accumulator, Combiner)
- Identity : 계산을 위한 초기값 (0으로 설정하면 요소가 없을 경우 0 반환)
- Accumulator : 중간 결과를 생성하기 위한 연산
- Combiner : 다른 스레드에서 실행한 결과 합치는 것(parallelStream에서만 작동)
- count(), sum()은 집계 내부에 reduce() 포함
int[] arr={1,2,3,4,5,6};
int result1=Arrays.stream(arr).reduce(0, (a,b)->a+b)
- collect()
- List, Set, Map 등 다른 컬렉션으로 결과를 가져올 때 사용
- Collectors 객체에서 static 메서드 사용 가능
- 없는 경우 Collector 인터페이스로 구현 가능
int[] arr={1,2,3,4,5,6};
List<Integer> list=Arrays.stream(arr).collect(Collectors.toList());
Set<Integer> set = Arrays.stream(arr).collect(Collectors.toCollection(HashSet::new);
Optional
- NullPointerException(NPE) null 값으로 인한 에러를 객체 차원에서 방지
- 연산 결과를 Optional에 담아서 반환하면 NPE 방지
Optional
- 모든 타입의 객체를 담을 수 있는 Wrapper class
- public final class Optional { private final T value; // T타입의 참조 변수 }
- Optional 객체 생성
- of() : null 값을 인자로 받는 경우 에러 발생
- ofNullable() : null 값도 받아들임
Optional<String> opt1 = Optional.of("Yes");
Optional<String> opt2 = Optional.of(null); // 오류 발생
Optional<String> opt3 = Optional.ofNullable(null);
System.out.println(opt1); // Optional[Yes] 출력
System.out.println(opt1.get()); // Yes 출력
System.out.println(opt1.isPresent()); //null이 아니면 true, null이면 false 반환
opt1.ifPresent(s-> System.out.println(s)); //null 값이 아니면 출력
String nullname=null;
String example = Optional.ofNullable(nullName).orElse("default");
//null 유무에 상관 없이 불러서 디폴트로 설정 (아닐경우를 대비해 미리 설정)
String example = Optional.ofNullable(nullName).orElseGet(()->"default");
//null일 경우에만 가져옴 (아닐 경우에 가져옴)
opt1.<String>empty(); //기본값으로 초기화
- Optional 심화
- map() : Optional.of로 감싸서 반환
- flatmap() : 그냥 반환
- import lombok으로 @Getter, @AllArgsConstructor로 자동 getter, constructor 생성 가능
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Topic{
String todayTopic;
}
@Getter
@AllArgsConstructor
public class MathField{
Optional<Topic> topic;
}
@Getter
@AllArgsConstructor
public class MathTeacher{
String name;
String id;
Optional<MathField> mathField;
}
public class MakingSystem{
public Optional<MathTeacher> makeMathTeacher(String name){
Optional<Topic> topic = Optinal.of(new Topic("math1"));
Optional<MathField> mathField = Optional.of(new MathField(topic));
return Optional.of(new MathTeacher(name, "0139", mathField));
}
}
public class OptionalExample{
public static void main(String[] args){
MakingSystem makingSystem = new MakingSystem();
String todayTopic= makingSystem
.makeMathTeacher("John")
.flatMap(MathTeacher::getMathField)
.flatMap(MathField::getTopic)
.map(Topic::getTodayTopic);
.orElseGet("Null");
System.out.println(todayTopic); // math1 출력
}
}
4. 파일 입출력(I/O)
개요 및 학습 목표
- 바이트 기반 스트림의 입출력 코드
- 문자 기반 스트림의 입출력 코드
- 파일 클래스
InputStream, OutputStream
입출력
- InputStream, OutputStream으로 데이터 단방향 전송
- 입출력 대상
- File : FileInputStream / FileOutputStream
- 프로세스 : PipedInputStream / PipedOutputStream
FileInputStream
- 터미널에서 echo hello, world >>hello.txt
- FileInputStream : 파일 내용을 stream에 읽는 스트림
- BufferedInputStream : 버퍼는 바이트 배열로 많은 바이트를 저장하여 한 번에 많은 양을 처리하여 데이터 입출력을 도와주는 임시 저장 공간으로 성능 향상 기여
import java.io.FileInputStream;
import java.io.BufferedInputStream;
public class FileInputStream{
public static void main(String[] args){
try{
FileInputStream fileInput =new FileInputStream("hi.txt"); // FileInputStream클래스 생성
BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
int i=0;
while((i=bufferedInput.read())!=-1){ // 스트림에서 읽어들이고 -1이면 나온다
System.out.print((char)i);
}
fileInput.close(); // 스트림 닫기
}
catch(Exception e){
System.out.println(e);
}
}
}
FileOutStream
import java.io.FileOutputStream;
public class FileOutputStream{
public static void main(String[] args){
try{
FileOutputStream fileOutput =new FileOutputStream("hi.txt"); // FileOutputStream클래스 생성
String str="World!";
for(byte b : str.getBytes())
fileOutput.write(b);
fileOutput.close(); // 스트림 닫기
}
catch(Exception e){
System.out.println(e);
}
}
}
FileReader, FileWriter
- FileReader/FileWriter
- FileInputStream과 FileOutputStream은 1바이트 기준으로 입출력을 진행하는 바이트 기반
- char 타입은 2byte로 문자 기반 입출력을 위해 FileReader. FileWriter를 사용 가능
- FileReader는 인코딩을 유니코드(UTF-16)로 변환
- FileWriter는 유니코드를 인코딩으로 변환
FileReader
import java.io.FileReader;
import java.io.BufferedReader;
public class FileReaderEx{
public static void main(String[] args){
try{
FileReader fileReader =new FileReader("hi.txt"); // FileReader클래스 생성
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while((i=bufferedReader.read())!=-1){ // 스트림에서 읽어들이고 -1이면 나온다
System.out.print((char)i);
}
fileReader.close(); // 스트림 닫기
}
catch(Exception e){
System.out.println(e);
}
}
}
FileWriter
import java.io.FileWriter;
public class FileWriterEx{
public static void main(String[] args){
try{
FileWriter fileWriter =new FileWriter("hi.txt"); // FileWriter클래스 생성
String str="Hello, world!";
fileWriter.write(str);
fileWriter.close(); // 스트림 닫기
}
catch(Exception e){
System.out.println(e);
}
}
}
File 클래스
- File class
- Fileclass 사용 예제
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
File file = new File("./src/hi.txt");
File newFile = new File("./src/", "hello.txt"); // 부모경로와 파일명을 입력
newFile.createNewFile(); // 새로운 파일 생성
System.out.println(file.getPath()); // file에 입력된 경로를 문자옇 형태로 반환
System.out.println(file.getParent()); //file에 입력된 부모 경로명을 문자열 형태로 반환
System.out.println(file.getCanonicalPath()); // 파일의 canonical경로를 반환
System.out.println(file.canWrite()); // 파일을 쓸 수 있는 지 여부 반환
}
}
//출력
//.\\src\\hi.txt
//.\\src
//C:\\Users\\user\\IdeaProjects\\Example\\src\\hi.txt
//true
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
//IOException 발생시 해당 클래스 벗어남
//try catch문으로 예외 처리 가능
File dir = new File("./src/"); // 부모 디렉터리를 File 객체로 생성
File [] files = dir.listFiles(); // listFiles()로 그 안의 모든 내용을 File list로 생성
String suffix = " World!"; // 이름 뒤에 붙일 문자열
for(int i=0; i<files.length; i++) {
String fileName=files[i].getName(); // getName()으로 파일 이름 가져오기
if (fileName.endsWith("txt")){ //txt로 끝나는 파일 선택
files[i].renameTo(new File(dir, fileName.substring(0,fileName.length()-4)+suffix+".txt"));
//renameTo()로 바꿀 파일을 익명 클래스로 입력
}
}
}
}