// ========= 요리의 이름들만 추출해서 매핑 ========
// 1. 정석
// 요리에 이름만 추출하고 싶다.
// 1) Map()을 사용하기 위해, Map 메소드를 내장하는 stream 객체로 변환해준다.
List<String> menuFinal = menuList.stream()
// 2) map() 메소드를 오버라이딩 해준다. 이 때, 매개변수는 Function 클래스이다.
.map(new Function<Dish, String>() {
@Override
public String apply(Dish dish) {
return dish.getName();
}
// 3) .collect(Collectors.toList()) 로 List로 변환해준다. (안할 시 주소만 출력됨)
}).collect(Collectors.toList());
// 2. 람다식으로 변경
List<String> dishNameList = menuList.stream()
.map((menu) -> menu.getName())
.collect(toList());
// ======== 요리 중에 요리이름과 칼로리만 추출해서 새로운 객체로 포장하여 배열에 담고싶음 ===== //
// 1. 익명 클래스 버전
List<DishDetail> collect = menuList.stream()
.map(new Function<Dish, DishDetail>() {
@Override
public DishDetail apply(Dish dish) {
// dish.getCalories()와 dish.name()을 추출해야 되는데, 두 개를 한 번에 추출 불가
// => 따라서, 두 정보를 담은 객체를 만들어서, 그 객체를 반환하도록 한다.
return new DishDetail(dish);
}
})
.collect(toList()); // 이걸 System.out.println()을 하면, 각 데이터 요소의 경우 toString()이 자동 적용된다.
System.out.println(collect);
// 2. 람다식 표헌
List<SimpleDish> simpleDishes = menuList.stream()
.map(menu -> new SimpleDish(menu))
.collect(toList());
simpleDishes.forEach(System.out::println);
stream().filter().collect(Collectors.comparing())
자세한 원리는 아래 예시 주석 참고
// 1. 정석버전(원리 설명용)
menuList.stream() // 1) filter, map 등의 기능을 사용하기 위해 stream 객체를 만들고
// 2) stream 객체의 메소드인 map()을 활용. 이 때, 매개변수로는 Predicate 객체를 받음
// (상세설명1) 이 때, 사용자가 predicate 객체를 새로 생성하면서 test 함수를 오버라이딩 하면
.filter(new Predicate<Dish>() {
@Override
public boolean test(Dish dish) {
return dish.getCalories() > 300;
}
}) // (상세설명2) filter() 함수의 내부 작동 원리에 따라, stream으로 만든 collection의 각 데이터 요소를 받아서
// 위에서 오버라이딩한 test() 메서드에 argument로 전달
// 그렇게 해서 return 된 값을 바탕으로 내부 구현 원리에 따라 필터링 된 값만 반환함
.limit(3)
.collect(toList());
// 2. 람다버전
List<Dish> limit3 = menuList.stream()
.filter(m -> m.getCalories() > 300)
.limit(3) // 앞에서부터 3개 선택
.collect(toList());
### 2. ➕ 같이 쓸 수 있는 stream 내장 메서드 : skip, limit
<br><br>
## [ ArrayList의 정렬 : Sort ]
### - 1. 기본구조
- List에 쓰는 것이다.** 예를 들어 List에 필터링을 한 후 sort를 하고 싶을 때는,필터링을 하기 위해서 stream 객체로 바꾼 후 filtering 진행 하므로, 이 때는 sort 못 쓰고 sorted를 써야 한다.**
- `List.sort(Comparator.comparing())`
- 원리 : 1) sort안에 Comparator 객체를 새로 생성하고
2) 기존 Comparator 객체의 comparing 메서드를 내가 원하는 정렬 기준으로 override해준다.
```java
studentList.sort(new Comparator<Student>() {
// sort 함수의 내부 구현 코드에 의해서, 1) studentLilst를 순회하면서 배열을 순서대로 돌면서 Student 객체를 가져와서
@Override
// 2) if (compare() > 0) 이면 정렬 순서를 바꾼다.
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
```
### - 2. 람다식 식 람다식 함축표현
```java
// 2. 람다식 : .sort(Comparator.comparing(parameter))
// => comparing안에 parameter로 객체를 만들어 준 후, 기존의 메소드를 오버라이딩 해준다.
studentList.sort(Comparator.comparing((student) -> student.getAge()));
// 4. 위 식을 ::로 표현
studentList.sort(Comparator.comparing(Student::getAge));
Collection.stream().sorted(Comparator.comparing(Comparator 객체)).reversed().collect(Collectors.toList());
// 메뉴들을 이름 내림차로 정렬 (zyx순)
menuList.stream() // 1) sorted를 사용하기 위해서는 먼저 sorted 메서드를 내장하고 있는 stream 객체로 변환해줘야 한다.
// 2) sorted(Comparator.comparing(Comparator c)로 정렬
// - 작동원리 : sorted 함수 내부 작동원리에 의하여,
// 1) menuList의 각 데이터 요소를 가져와서
// 2) 사용자가 오버라이딩한 Comparator.comparing() 메소드를 호출한 후
// 3) return 값을 활용하여 정렬한다.
.sorted(Comparator.comparing((Dish dish) -> dish.getName()).reversed())
.collect(toList())
.forEach(System.out::println);
// anyMatch()
// 요리 중 채식주의자가 먹을 수 있는 요리가 하나라도 있는지 여부
boolean flag1 = menuList.stream()
// .filter(d -> d.getType() == DishType.MEAT)
.anyMatch(d -> d.isVegetarian());
// allmATCH()
System.out.println("flag1 = " + flag1);
// 요리 중 모든 요리가 1000칼로리 미만입니까?
boolean flag2 = menuList.stream()
.allMatch(m -> m.getCalories() < 1000);
System.out.println("flag2 = " + flag2);
// 요리 중에 첫번째 발견된 생선 요리를 찾기
Optional<Dish> firstFish = menuList.stream()
.filter(m -> m.getType() == DishType.FISH)
.findFirst();
firstFish.ifPresent(fish -> System.out.println(fish.getName()));