소스 코드가 컴파일되거나 실행될때 컴파일러 및 다른 프로그램에게 필요한 정보를 전달해주는 문법 요소
표준 애너테이션 : JDK에 내장
public class AnnotationTest {
public static void main(String[] args) {
SuperClass superClass = new SuperClass();
SubClass subClass = new SubClass();
superClass.example();
subClass.example();
}
}
class SuperClass {
public void example() {
System.out.println("SuperClass example method");
}
}
class SubClass extends SuperClass {
@Override
public void example() {
System.out.println("SubClass example method");
}
}
@Deprecated : 기존 사용하던 기술이 다른 기술로 대체되어 기존 기술을 적용한 코드를 더이상 사용하지 않도록 유도하는 경우 사용
@SuppressWarnings : 특정 컴파일 경고 메세지를 지정하여 나타나지 않도록 함
@FunctionalInterface : 함수형 인터페이스를 선언할 때 선언이 올바르게 되었는지 확인하도록 함
메타 애너테이션 : 다른 애너테이션을 정의할때 사용
사용자 정의 애너테이션
메서드를 하나의 '식(expression)'으로 표현한 것. 간결하고 명확하게 표현 가능
람다식은 익명 메서드이자 익명 클래스로부터 생성된 객체이다.
익명 클래스는 객체의 선언과 생성을 동시에 하며 오직 하나의 객체를 생성되고 단 한번만 사용되는 클래스이다.new 인터페이스명() {
익명 클래스 내용
}
람다식을 사용하기 위하여 1:1로 대응하는 함수형 인터페이스가 필요
기본 제공되는 함수형 인터페이스를 사용하여 함수형 인터페이스 작성 생략 가능
public class LambdaTest {
public static void main(String[] args) {
// 람다식을 Object 타입의 참조변수에 할당해도 sum 메서드를 호출 할 수 없다
// Object object = new Object() {
// int sum(int num1, int num2)
// return num1 + num2;
// }
// };
// System.out.println(object.sum);
ExampleFunction1 exampleFunction1 = (int num1, int num2) -> num1 + num2;
System.out.println(exampleFunction1.example1(10, 15) + "\n");
// 출력 : 25
ExampleFunction2 exampleFunction2 = () -> System.out.println("example2 호출 \n");
exampleFunction2.example2();
// 출력 : example2 호출
ExampleFunction3 exampleFunction3;
exampleFunction3 = (x) -> {
int result = x * 5;
System.out.println(result);
};
exampleFunction3.example3(10);
// 출력 : 50
exampleFunction3 = (x) -> System.out.println(x * 10 + "\n");
exampleFunction3.example3(10);
// 출력 : 100
ExampleFunction4 exampleFunction4 = (x, y) -> x * y;
System.out.println(exampleFunction4.example4(3, 2) + "\n");
// 출력 : 6
ExampleFunction4 exampleFunction4_1 = (x, y) -> exampleFunction4.example4(sum(x, y), y);
System.out.println(exampleFunction4_1.example4(3, 3));
// 출력 : 18
//
}
static int sum(int x, int y) {
return x + y;
}
}
@FunctionalInterface
interface ExampleFunction1 {
int example1 (int num1, int num2);
}
interface ExampleFunction2 {
void example2 ();
}
interface ExampleFunction3 {
void example3 (int x);
}
interface ExampleFunction4 {
int example4 (int x, int y);
}
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
public class MethodReferenceTest {
public static void main(String[] args) {
// Ex1 ex1 = ((x, y) -> Math.max(x, y));
Ex1 ex1 = Math::max;
System.out.println(ex1.exMethod1(123, 400) + "\n");
// IntBinartOperator : 두 정수 값을 받아 연산을 하고 정수형 결과값을 생산하는 인터페이스
IntBinaryOperator operator;
// Ex2클래스의 정적 메서드 참조
operator = Ex2::exMethod2;
System.out.println(operator.applyAsInt(5, 8) + "\n");
// Ex2클래스의 인스턴스 메서드 참조
Ex2 ex2 = new Ex2();
operator = ex2::exMethod3;
System.out.println(operator.applyAsInt(5, 8) + "\n");
// 생성자 참조
// Function<T, R> : T타입을 인자로 받아 R타입을 반환하는 인터페이스
Function<String, ConstructorRefer> function1 = ConstructorRefer::new;
ConstructorRefer person1 = function1.apply("4885");
// 출력 : ConstructorRefer(String id) !!
// String 값을 입력받아 ConstructorRefer 객체를 생성하는 함수를 표현하는 function1 변수를 선언하고
// 이 함수를 구현하는데 ConstructorRefer 클래스의 생성자를 사용하겠다
// BiFunction<T, U, R> T, U타입을 인자로 받아 R타입을 반환하는 인터페이스
BiFunction<String, String, ConstructorRefer> function2 = ConstructorRefer::new;
ConstructorRefer person2 = function2.apply("4885", "하정우");
// 출력 : ConstructorRefer(String name, String id) !!
// String, String 값을 입력받아 ConstructorRefer 객체를 생성하는 함수를 표현하는 function2 변수를 선언하고
// 이 함수를 구현하는데 ConstructorRefer 클래스의 생성자를 사용하겠다
}
}
interface Ex1 {
int exMethod1(int x, int y);
}
class Ex2 {
public static int exMethod2(int x, int y) {
return x * y;
}
public int exMethod3(int x, int y) {
return x + y;
}
}
class ConstructorRefer {
private String name;
private String id;
public ConstructorRefer() {
System.out.println("ConstructorRefer() !!");
}
public ConstructorRefer(String id) {
System.out.println("ConstructorRefer(String id) !!");
this.id = id;
}
public ConstructorRefer(String name, String id) {
System.out.println("ConstructorRefer(String name, String id) !!");
this.name = name;
this.id = id;
}
}
배열 및 컬렉션의 저장 요소를 하나씩 참조해 람다식으로 처리할 수 있도록 하는 반복자
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamProducing {
public static void main(String[] args) {
ArrayList<String> numList = new ArrayList<>();
numList.add("one ");
numList.add("two ");
numList.add("three\n");
String[] numArr = {"one ", "two ", "three\n"};
// 스트림 생성
Stream<String> listStream = numList.stream();
Stream<String> arrStream = Arrays.stream(numArr);
Stream<String> arrStream2 = Stream.of(numArr);
// IntStream ints = new Random().ints(); // 무한 스트림
IntStream ints2 = new Random().ints(5); // 스트림 생성 범위 제한
IntStream ints3 = new Random().ints().limit(5);
IntStream ints4 = IntStream.range(1, 10); // 특정 범위 지정 // rangeClosed는 두번째 인자까지 포함
// 출력
listStream.forEach(System.out::print); // one two three
System.out.println();
arrStream.forEach(System.out::print); // one two three
System.out.println();
// ints.forEach(System.out::print);
ints2.forEach(System.out::println);
System.out.println();
ints3.forEach(System.out::println);
System.out.println();
ints4.forEach(System.out::print); // 123456789
}
}
조건에 맞는 데이터 정제
import java.util.Arrays;
import java.util.List;
public class FilterTest {
public static void main(String[] args) {
List<String> names = Arrays.asList("오태식 ", "남춘식 ", "곽두팔 ", "김창식 ", "남춘식 ", "남봉헌");
names.stream()
.distinct() // 중복 제거
// .forEach(System.out::println);
.forEach(element -> System.out.print(element));
// 오태식 남춘식 곽두팔 김창식 남봉헌
System.out.println();
names.stream()
.filter(element -> element.startsWith("남"))
.forEach(element -> System.out.print(element));
// 남춘식 남춘식 남봉헌
System.out.println();
names.stream()
.distinct()
.filter(element -> element.startsWith("남"))
.forEach(element -> System.out.print(element));
// 남춘식 남봉헌
}
}
원하는 필드만 추출 혹은 특정 형태로 변환
import java.util.Arrays;
import java.util.List;
public class MapTest {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple ", "strawberry ", "peach ", "orange ");
fruits.stream()
.map(String::toUpperCase) // .map(element -> element.toUpperCase()) // 메서드 참조
.forEach(System.out::print); // .forEach(element -> System.out.print(element));
// APPLE STRAWBERRY PEACH ORANGE
System.out.println();
List<Integer> nums = Arrays.asList(1, 3, 4, 6, 8, 9);
nums.stream()
.map(number -> number * 2)
.forEach(System.out::print);
// 268121618
}
}
import java.util.Arrays;
public class FlatTest {
public static void main(String[] args) {
String[][] names = {{"오태식 ", "남춘식 "}, {"곽두팔 ", "김창식 "}};
Arrays.stream(names)
.map(Arrays::stream)
.forEach(System.out::println);
// 주소값 출력됨
Arrays.stream(names)
.flatMap(Arrays::stream)
.forEach(System.out::print);
// 오태식 남춘식 곽두팔 김창식
// flatMap() : 중첩구조를 제거하고 단일 컬렉션으로 만들어줌
}
}
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortTest {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple ", "strawberry ", "peach ", "orange ");
fruits.stream()
.sorted() // 인자값 없는 sort() -> 오름차순
.forEach(System.out::print);
// apple orange peach strawberry
System.out.println();
fruits.stream()
.sorted(Comparator.reverseOrder()) // 내림차순
.forEach(System.out::print);
// strawberry peach orange apple
System.out.println();
fruits.stream()
.limit(2) // 일부를 자름 // apple strawberry
.skip(1) // 일부 요소를 건너뜀 // strawberry
.peek(System.out::print) // forEach()와 같이 요소들을 순회하며 작업 수행하지만
.forEach(System.out::print); // 중간 연산자로 여러번 연결하여 사용 가능
}
}
최종 연산 후 스트림 파이프라인이 닫히고 사라짐
import java.util.Arrays;
public class Basic {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
// 카운트
long count = Arrays.stream(numbers).count();
System.out.println(count); // 5
// 합계
int sum = Arrays.stream(numbers).sum();
System.out.println(sum); // 15
// 평균
double average = Arrays.stream(numbers).average().getAsDouble();
System.out.println(average); // 3.0
// 최대값
int max = Arrays.stream(numbers).max().getAsInt();
System.out.println(max); // 5
// 최소값
int min = Arrays.stream(numbers).min().getAsInt();
System.out.println(min); // 1
// 배열 첫번째 요소
int first = Arrays.stream(numbers).findFirst().getAsInt();
System.out.println(first); // 1
}
}
특정 조건을 충족하는지 검사, boolean 타입으로 반환
import java.util.Arrays;
public class matchTest {
public static void main(String[] args) {
int[] arr = {2, 4, 6};
Boolean result = Arrays.stream(arr).allMatch(element -> element % 2 == 0);
System.out.println(result); // 모든 요소가 조건을 만족하는지 // true
result = Arrays.stream(arr).anyMatch(element -> element % 3 == 0);
System.out.println(result); // 하나의 요소라도 조건을 만족하는지 // true
result = Arrays.stream(arr).noneMatch(element -> element % 2 == 0);
System.out.println(result); // 모든 요소가 조건을 만족하지 않는지 // false
}
}
스트림 요소를 줄여나가며 연산 수행 후 최종결과 반환
import java.util.Arrays;
public class ReduceTest {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
long result = Arrays.stream(arr).sum();
System.out.println(result);
// 15
int sum1 = Arrays.stream(arr)
.map(element -> element * 2)
.reduce((a, b) -> a + b)
.getAsInt();
System.out.println(sum1);
// 30
int sum2 = Arrays.stream(arr)
.map(element -> element * 2)
.reduce(3, (a, b) -> a + b); // a : 누적된 값, b : 더할 값
System.out.println(sum2);
// 33
}
}
Collectors 클래스에 여러 메서드 정의
스트림의 요소들을 List, Set, Map 등 다른 타입의 결과로 수집
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CollectTest {
public static void main(String[] args) {
List<Flower> flowerList = Arrays.asList(
new Flower("매화", 2, Flower.Season.Winter),
new Flower("벚꽃", 4, Flower.Season.Spring),
new Flower("데이지", 5, Flower.Season.Spring),
new Flower("장미", 8, Flower.Season.Summer)
);
Map<String, Integer> springMap = flowerList.stream()
.filter(s -> s.getSeason() == Flower.Season.Spring)
.collect(Collectors.toMap(
flower -> flower.getName(), // Key
flower -> flower.getMonth() // Value
));
System.out.println(springMap);
// {데이지=5, 벚꽃=4}
}
}
class Flower {
public enum Season {Spring, Summer, Fall, Winter}
private String name;
private int month;
private Season season;
public Flower(String name, int month, Season season) {
this.name = name;
this.month = month;
this.season = season;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public Season getSeason() {
return season;
}
public void setSeason(Season season) {
this.season = season;
}
}