Fact
- 아침에 Java로 문제를 풀었다. 하나는 제일작은 수 제거하기 그리고 하나는 정수 내림차순으로 배치하기 이다. 제일 작은 수 제거하기를 하기 위해서 list로 변환 해서 collection method를 써서 min 을 찾은 후에 지웠다. 그런 후에 다시 int[] 로 변환 작업을 거쳤다. 4줄이나 나왔다. 다른 사람 코드를 봤는데 그중 stream으로 하는 방법을 봤다. 그건 아주 깔끔하게 나왔다. 풀이 방법은 stream으로 변환하고 min 값을 구한후에 stream min 값을 int min 값으로 바꿨다. 그후에 주어진 배열을 stream으로 변환하고 min 을 없애기 위해서 filter를 한 후에 다시 배열로 만들어서 반환했다. 두번째 문제는 long의 input 값이 주어 줬는데 이것을 string으로 바꾸기 위해서 int 로 바꿨다가 썼었는데 이것 때문에 값이 잘려서 나중에 원하는 결과가 안나왔었다.
- java로 문제 풀이 외에 javaScript를 오랜만에 만져 봤다. 결과적으로 못풀었다. 효율성 문제가 아니였는데 시간 초과가 떴다.
- 오늘은 스터디를 했고 그 후에 코어 자바 9 8장을 읽으면서 마저 정리를 했다.
Feelings
- 탐욕 문제 너무 어렵다. java 타입 변환도 너무 어렵다.
- 책도 너무 어렵다 다 어렵다.
Findings
- 스트림 데이터에서 결과를 얻기 위해서 리덕션을 쓴다. 리덕션은 종료 연산이다.
- 리덕션 중 max min 은 최대값 최소값을 주지만 Optional
로 반환한다.
List<String> b = Arrays.asList(new String[] {"ZZ","Zxz","A"});
b.stream().max(Comparator.comparing(String::valueOf)); //Optional[Zxz]
List<String> b = Arrays.asList(new String[] {});
b.stream().max(Comparator.comparing(String::valueOf)).orElse("orElse activated");// "orElse activated"
boolean aWordStartsWithQ = b.stream().anyMatch(s -> s.startsWith("Q")) // false
Optional<String> startsWithQ = b.stream().parallel().filter(s -> s.startsWith("Z")).findAny(); // "ZZ"
optional 값을 사용하는 방법이 다양하다.
orElse, orElseGet, orElseThrow, ifPresent, ifPresentOrElse, optionalValue.map등이 있다.
orElse는 옵션 값으로 래핑된 것이 없다면 orElse로 지정한것을 반환한다.
orElseGet는 orElse와 비슷하지만 지정한것을 가져온다.
orElseThrow는 정의한 error을 던져 준다.
ifPresent는 래핑된 값이 있을 시에 지정한것을 실행한다.
ifPresentOrElse는 있으면 실행 없으면 다른것을 실행 할 수 있게끔 정의 할 수 있다.
List<String> b = Arrays.asList(new String[] {});b.stream().max(Comparator.comparing(String::valueOf)).orElse("asdasd"); //asdasd
Optional<String> result2 = optionalString.or(() ->
Optional.ofNullable(System.getProperty("myapp.default")));// myapp.default가 있었으면 그에 대한 property가 나오고 아니면 없다면 Optional.empty 값이 저장된다.
Optional<String> result3 = b.stream().filter(s -> s.contains("red")).findFirst();// 단어에 red가 들어 있다면 그 단어 전체가 된다. 없으면 값은 Optional.empty
result3.ifPresent(s -> System.out.println(s + "hello" ));// result3 가 empty가 아닐시에 result3 + hello 가 출력된다. empty면 아무것도 안한다.
optionalValue.ifPresentOrElse(
s -> System.out.println(s + " contains blue"),
() -> System.out.println("Nothing contains blue"));
// optionalValue가 있으면 s -> ...을 처리하고, 아니면 () -> ... 을 실행한다.
Optional 값을 돌려주는 메서드를 반복할 수 있다. 그때 쓰는게 flatMap이다. flatMap은 연쇄적으로 호출해서 파이프라인을 구성할 수 있다. 파이프라인 한 곳에서 문제가 생길시에 Optional.empty 가 뜨고 아니면 그대로 처리한다.
//inverse, OptionalDemo, squareRoot가 정의 되어 있다고 치자.
System.out.println(inverse(4.0).flatMap(OptionalDemo::squareRoot));// Optional[0.5]
System.out.println(inverse(-4.0).flatMap(OptionalDemo::squareRoot));// Optional.empty
Optional<Double> result3 = Optional.of(-4.0).flatMap(OptionalDemo::inverse)
.flatMap(OptionalDemo::squareRoot);// squareRoot가 통과가 안된다.
System.out.println(result3);//Optional.empty
stream 메서드는 Optional 결과를 반환하는 메서드를 사용할때 유용하다.
//설정1
User[] users = {
new User("gboole", "George Boole"),
new User("achurch", "Alonzo Church"),
new User("hcurry", "Haskell Curry")
};
//설정2
Optional<User> lookup(String id) {
return Stream.of(users).filter(u -> u.getId().equals(id)).findFirst();
}
//flatmap 안쓸시
Stream<String> ids = Stream.of("gboaole", "gboole");
Stream<User> users = ids.map(Users::lookup)
.filter(Optional::isPresent)
.map(Optional::get);
show("users", users);// users:1 [George Boole]
//flatmap 쓸시
Stream<String>ids = Stream.of("achurch", "hc1urry");
Stream<User>users = ids.map(Users::lookup)
.flatMap(Optional::stream);
show("users", users);// users:1 [Alonzo Church]
스트림 요소들을 방문 하는데 사용 하는 전통적인 반복자는 iterator 메서드이다.
Iterator<Integer> iter = Stream.iterate(0, n -> n + 1).limit(10).iterator();
while (iter.hasNext()){
System.out.print(iter.next());//0123456789
}
Object[] numbers = Stream.iterate(4, n -> n + 1).limit(10).toArray();
System.out.println(Arrays.toString(numbers)); //[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
//혹은 Integer[]로 만들고 싶을때
Integer[] numbers3 = Stream.iterate(4, n -> n + 1).limit(10).toArray(Integer[]::new);
System.out.println(Arrays.toString(numbers3));//[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
stream 요소들을 다른 대상으로 모을때 COllector 인터페이스의 인스턴스를 받는 collect 메서드를 사용 하면 편하다.
List<String> result = new ArrayList<>(Arrays.asList(new String[]{"1", "2"}));
HashSet<String> asq = result.stream().collect(HashSet::new, HashSet::add, HashSet::addAll);// [1, 2] hashSet
Set<String> asd = result.stream().collect(Collectors.toSet()) // [1, 2] Set
TreeSet<String> asd = result.stream().collect(Collectors.toCollection(TreeSet::new)); // [1, 2] TreeSet
stream에서 요소들 joining 하기
List<String> result = new ArrayList<>(Arrays.asList(new String[]{"1", "2"}));
result.stream().collect(Collectors.joining())// "12"
result.stream().collect(Collectors.joining(","))//"1,2"
result.stream().limit(1).collect(Collectors.joining(","))//"1"
맵으로 모으기
Collectors.toMap 메서드는 각각 맵의 키와 값을 만들어 내는 함수 두개를 인수를 받는다.
Future Action
- javaScript 오랜만에 풀었는데 못 풀었다. 숙련도가 떨어져서 그럴 수도 있어서 다음에는 javaScript문제도 풀어보면서 숙련도를 유지 할 수 있게끔 만들자.
- 책을 따라 코드를 쳐 보는 것도 좋지만 어디엔가 적용을 해보면 더 기억에 남을것 같다. 다음엔 어디에다 적용을 해보면서 공부를 해보도록 하자.