다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능을 의미
객체 타입을 컴파일 시에 체크하여 안정성이 높아진다. -> 의도하지 않은 타입의 객체가 저장되는 것을 막고 잘못된 형변환을 막는다.
public class 클래스명<T> {...}
public interface 인터페이스명<T> {...}
- <T> == Type
- <E> == Element
- <K> == Key
- <V> == Value
- <N> == Number
- <R> == Result
람다식은 식별자 없이 실행 가능한 함수
함수의 이름을 따로 정의하지 않아도 곧바로 함수처럼 사용 가능하다.(익명함수라고도 부른다)
문법이 간결해 편리하다.
하지만 재사용이 불가능하고, 코드가 지저분해 질 수 있다.
[기존의 메소드 형식]
반환타입 메소드이름(매개변수 선언) {
수행 코드 블록
}
[람다식의 형식]
반환타입 메소드이름(매개변수 선언) -> {
수행 코드 블록
}
public class LambdaPrac {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("korea");
list.add("japan");
list.add("france");
Stream<String> stream = list.stream();
//여기서 lamda식은 list에서 하나씩 꺼내서 str변수에 저장해줘 -> 이걸 대문자로 바꿔줘
stream.map(str -> str.toUpperCase()).forEach(it -> System.out.println(it));
Stream<String> stream2 = list.stream(); //stream 한 번 사용하면 끝 다시 만들어줘야된다.
//길면 {}를 사용 대신 return 해줘야됨
stream2.map(str -> {
System.out.println(str);
return str.toUpperCase();
}).forEach(System.out::println);
System.out.println(list);
}
}
스트림은 곧 '데이터의 흐름'
컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자
스트림을 활용해서 필터링, 데이터 변경, 다른 타입이나 자료구조로 변환 등을 할 수 있다.
class Sale {
String fruitName;
int price;
float discount;
public Sale(String fruitName, int price, float discount) {
this.fruitName = fruitName;
this.price = price;
this.discount = discount;
}
}
public class StreamPrac {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("서울");
list.add("부산");
list.add("대구");
list.add("서울");
System.out.println(list);
System.out.println("\nlist에서 2개만 꺼내기");
List<String> result = list.stream() //list를 stream으로 바꾸고
.limit(2) //나는 2개만 꺼낼거야
.collect(Collectors.toList()); //이렇게 stream 처리된 애들을 하나로 모을건데 또 다른 리스트로 만들거야
System.out.println(result);
System.out.println("\nlist -> transformation -> set");
Set<String> set = list.stream()
.filter("서울"::equals)
.collect(Collectors.toSet());
System.out.println(set);
System.out.println("\narray -> transformation -> set");
String[] arr = {"SQL", "Java", "Python"};
Stream<String> stringStream = Arrays.stream(arr);
stringStream.forEach(System.out::println);
System.out.println("\nstream 활용");
List<Sale> sales = Arrays.asList(
new Sale("Apple", 5000, 0.05f),
new Sale("Orange", 4000, 0.2f),
new Sale("Grape", 2000, 0)
);
sales.stream().map(sale -> Pair.of(sale.fruitName, sale.price * (1 - sale.discount)))
.forEach(pair -> System.out.println(pair.getLeft() + " 실구매가 " + pair.getRight() + "원 입니다."));
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//첫번째 요소와 수행할 함수를 적으면 reduce 연산
System.out.println(intList.stream().reduce(0, Integer::sum)); //0+1 = 1 -> 1+2 = 3 -> 3+3 =6 ... => 55
List<String> names = Arrays.asList("김정우", "김호정", "이하늘", "이정희", "박정우", "박지현", "정우석", "이지수");
long count = names.stream()
.filter(name -> name.startsWith("이"))
.count();
System.out.println("\ncount = " + count);
}
}