glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-007] UnaryOperator에 대한 질문 #151

Closed undeadtimo closed 1 month ago

undeadtimo commented 2 months ago

Based on: #145 By @yngbao97

yngbao님의 글 잘 읽었습니다.

시간이 부족한 와중에도 좋은 글을 작성해주셔서 감사합니다.

덕분에 UnaryOperator 인터페이스에 대해 이해할 수 있게 되었습니다.

특히 UnaryOperator를 사용하면 map을 사용하는 것과 다르게 타입안정성이 보장된다는 것이 저에게 와닿았습니다.

프로그래머가 실수로 단항연산자를 잘못 작성하여 변수의 타입이 바뀌게 되는 경우, 해당 타입이 심지어 기존 list의 타입의 하위타입이라면 map을 이용하였을 경우, 의도치 않은 결과를 파악해내기 어려울 것입니다.

그러나, UnaryOperator가 있다면, 동일한 타입을 보장하기 때문에 애초에 다른 타입의 변수가 반환될일이 없어져서 의도치한은 에러를 사연에 방지할 수 있게 되는 것을 알았습니다.

그러나,

선언시 변수명에 신경을 쓴다면 단순히 컬렉션 map 메서드에 람다식을 바로 사용하는 것보다 직관적인 효과를 가질 수 있다.

이 부분에 대한 이해가 잘 되지 않아서 여쭤보려 합니다.

선언시 변수명에 신경을 쓴다는 것은 어떠한 의미인지, 변수명에 신경을 썼다고 해서 어떻게 직관적인 효과를 가지게 되는지 구체적으로 설명해주신다면, 감사드리겠습니다.

yngbao97 commented 2 months ago

질문주신 부분의 문장을 다시 보니 명확하게 이해하기에 모호한 부분이 있었던 것 같네요. 선언시 변수명에 신경쓴다는 의미는 특정 함수의 동작이 무엇을 의미하는지 변수이름에 드러나도록 작성한다는 뜻입니다. (여기서는 람다식으로 구현한 단항연산에 값을 갱신하는 내용이 포함되어 있다면 그 의미를 변수에 반영한다는 의미입니다.)

// map 메서드에 직접 람다식 구현부를 작성한 예시
List<Integer> newNums1 = Nums.stream().map(t -> t*2).toList();

// map 메서드 람다식 구현부에 UnaryOperator를 사용한 예시
UnaryOperator<Integer> getDouble = t -> t*2;
List<Integer> newNums2 = Nums.stream().map(t -> getDouble.apply(t)).toList();

글에서 사용했던 코드 예시 중 일부입니다. 단순히 map 메서드에 람다식을 적어넣은 첫번째 코드는 해당 식이 무엇을 의미하는지 직접 읽어보고 해석해야 합니다. 하지만 UnaryOperator를 구현한 getDouble는 두배값을 얻는다는 의미를 담아 변수명을 선언했기 때문에 사용시에 보다 직관적으로 값의 변화를 이해할 수 있습니다.

undeadtimo commented 2 months ago

저의 질문에 대한 명쾌한 답변 감사드립니다.

UnaryOperator를 사용할 때, 변수명을 람다식에 대한 직관적인 이해가 가능하도록 지어준다면, 값을 어떻게 변화할지를 쉽게 이해할 수 있겠군요.

UnaryOperater가 타입 안정성을 보장해주는 것 외에도 프로그래머가 코드를 이해할 때 빠르게 이해하도록 하는 장점도 있다는 것을 다시금 이해하게 되었습니다.

좋은 글에 이어서 좋은 답변 해주신 점 다시금 감사드립니다.