Written by
Poogle
on
on
2021.08.06 TIL
새롭게 배운 것 Done
운동
독서
알고리즘
코딩
Collection
- map, filter, foreach를 직접 구현해보기
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class MyCollection<T> {
private List<T> list;
public MyCollection(List<T> list) {
this.list = list;
}
//map 구현
public <U> MyCollection<U> map(Function<T, U> function) {
List<U> newList = new ArrayList<>();
foreach(d -> newList.add(function.apply(d)));
return new MyCollection<>(newList);
}
//filter 구현
public MyCollection<T> filter(Predicate<T> predicate) {
List<T> newList = new ArrayList<>();
foreach(d -> {
if (predicate.test(d)) newList.add(d);
});
return new MyCollection<>(newList);
}
//foreach 구현
public void foreach(Consumer<T> consumer) {
for (T data : list) {
consumer.accept(data);
}
}
}
- 예제 활용 1 - 문자열의 길이를 구하고 2로 나눈 나머지가 1인 것 출력
package com.programmers.java.collection;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
new MyCollection<>(Arrays.asList("A", "AB", "ABC", "ABCD", "ABCDE"))
.map(String::length)
.filter(i -> i % 2 == 1)
.foreach(System.out::println);
}
}
- 결과
1
3
5
- 예제 활용 2 - User 중 나이가 19세 이상인 것 출력
public class User {
private int age;
private String name;
public User(int age, String name) {
this.age = age;
this.name = name;
}
//getter를 쓰지 않고 나이에 관한 정보는 User만 알고 있도록 User에서 구현
public boolean isOver19() {
return age >= 19;
}
//toString 오버라이딩
@Override
public String toString() {
return name + " (" + age + ")";
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
new MyCollection<User>(
Arrays.asList(
new User(15, "A"),
new User(16, "B"),
new User(17, "C"),
new User(18, "D"),
new User(19, "E"),
new User(20, "F"),
new User(21, "G"),
new User(22, "H"),
new User(23, "I")
)
)
.filter(User::isOver19)
.foreach(System.out::println);
}
}
- 결과
E F G H I
Iterator
- 여러 데이터의 묶음을 풀어서 하나씩 처리할 수 있는 수단을 제공
next()
로 다음 데이터 조회, 역으로는 불가능hasNext()
있을 때만 조회- Iterator 직접 구현
- MyIterator interface
public interface MyIterator<T> {
boolean hasNext();
T next();
}
- 구현
public MyIterator<T> iterator() {
return new MyIterator<T>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public T next() {
return list.get(index++);
}
};
}
Stream
- Java 8 이상에서부터 사용 가능
Collections.stream()
- 데이터의 연속
System.in
,System.out
도 스트림- filter, map, forEach 같은 고차함수(함수를 인자로 받는 함수)
Stream 생성 방법 2가지: generate & iterate
Random r = new Random();
Stream.generate(r::nextInt)
.limit(10)
.forEach(System.out::println);
Stream.iterate(0, (i) -> i + 1) //초기값(seed), 어떤 값을 결과로 만들어낼지
.limit(10)
.forEach(System.out::println);
Stream 활용 1
Stream<Integer> s1 = Arrays.asList(1, 2, 3).stream();
Stream<Integer> s1 = Stream.of(1, 2, 3);
Stream<Integer> s1 = Arrays.stream(new int[]{1, 2, 3}).mapToObj(i -> Integer.valueOf(i));
IntStream s3 = Arrays.stream(new int[]{1, 2, 3});
// stream으로 List<Integer> 생성
List<Integer> list = Arrays.stream(new int[]{1, 2, 3}).boxed().collect(Collectors.toList());
// stream으로 Integer[] arr 생성
Integer[] arr = Arrays.stream(new int[]{1, 2, 3}).boxed().toArray(Integer[]::new);
Stream 활용 2
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import java.util.stream.Stream;
//주사위를 100번 던져서 6 나올 확률 구하기
Random r = new Random();
long count = Stream.generate(() -> r.nextInt(6) + 1)
.limit(100)
.filter(n -> n == 6)
.count();
System.out.println(count);
//1 ~ 9 사이 겹치지 않게 3개를 배열로 출력
Random r = new Random();
int[] arr = Stream.generate(() -> r.nextInt(9) + 1)
.distinct()
.limit(3)
.mapToInt(i -> i)
.toArray();
System.out.println(Arrays.toString(arr));
//0 ~ 200 사이 랜덥값 5개를 뽑아 큰 순서대로 표시
Random r = new Random();
int[] arr = Stream.generate(() -> r.nextInt(200))
.limit(5)
.sorted(Comparator.reverseOrder())
.mapToInt(i -> i)
.toArray();
System.out.println(Arrays.toString(arr));
Optional
- 자바에거는 거의 모든 것이 레퍼런스 -> 거의 모든 것이 null이 될 수 있음
- ⚠ 항상 null인지 확인해야 함, 안 그러면 NPE(Null Pointer Exception)
- ⏩ 1. EMPTY 객체를 만들어서 사용
- ⏩ 2. Optional 사용
Optional<User> optionalUser = Optional.empty(); optionalUser = Optional.of(new User(27, "Poogle")); if (optionalUser.isPresent()) { //do1 } else { //do2 } if (optionalUser.isEmpty()) { //do2 } else { //do1 } optionalUser.ifPresent(user -> { //do1 }); optionalUser.ifPresentOrElse(user -> { //do1 }, () -> { //do2 });
- 되도록 null을 사용하지 않는 추세
실습 프로젝트
- 라이브러리 검색
- 설계 - 숫자 야구 게임
- 요구사항 파악
- 게임 룰 이해
- 동작 환경, 데이터 범위
- 3자리 숫자
- 중복 X
- 1 ~ 9, (0 사용 X)
- console 동작
- 일을 객체로 나누기 / 객체를 연관 짓기
- 핵심 로직 설계
- Flow Chart
- 요구사항 파악
- 구현 중 유의사항
private BallCount ballcount(Numbers answer, Numbers inputNumbers) {
int strike = 0; // 동기화 기능을 추가하기
int ball = 0;
answer.indexedForEach((a, i) -> {
inputNumbers.indexedForEach((n, j) -> {
if (!a.equals(n)) return;
if (i.equals(j)) strike += 1; //scope 밖에 있는 변수 읽기는 가능하지만 사용은 X -> 멀티 쓰레드 환경에서
else ball += 1;
});
});
return new BallCount(strike, ball);
}
- 비즈니스 로직에 따라 변경 하면서 구현하기
- 생성자 주입 -> 의존성을 낮춤
- Faker를 쓰는 부분 -> 엔진 밖에 있어야겠음
- 핵심 비즈니스 로직은 외부에 의한 의존도를 낮추기 위해 분리한 것
- 내가 만든 모델, 로직 캡슐레이션
깨달은 점 FEELING
- 항상 자바 8 버젼으로 플젝들을 했더니 처음에 jdk 설정 때문에 많이 애먹었다. 정확한 문제가 뭐였는지 파악하진 못했지만 아마도…
- 이 두 곳 모두에서 그 설정을 변경했어야 하는데 하나만 해서 그런게 아닐까 싶다.