반응형

스터디 50

[Effective Java] Item 76. 가능한 한 실패 원자적으로 만들라

실패 원자적 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다는 내용입니다. 실패 원자적으로 만드는 방법 불변 객체로 설계 불변 객체는 태생적으로 실패 원자적입니다. 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일이 없습니다. 불변 객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문입니다. 작업 수행에 앞서 매개변수의 유효성 검사 public Object pop() { if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null; // 다쓴 참조 해제 return result; } if 문이..

[Effective Java] Item49. 매개변수가 유효한지 검사하라

매개변수를 제대로 검사하지 않으면? 메서드 수행 중간에 모호한 예외를 던질 수 있습니다. 메서드가 잘못된 결과를 반환할 수 있습니다. 잘못된 결과를 반환하므로 이후에 알 수 없는 시점에 이 메서드와 관련없는 오류를 낼 수 있습니다. public과 protected 메서드는 매개변수 값이 잘 못 됐을 때 던지는 예외를 @throws 자바독 태그를 이용해 문서화해야 합니다. 매개변수의 제약을 문서화한다면 그 제약을 어겼을 때 발생하는 예외도 함께 기술해야합니다. /** * Returns a BigInteger whose value is {@code (this mod m}). This method * differs from {@code remainder} in that it always returns a * ..

[Effective Java] Item48. 스트림 병렬화는 주의해서 사용하라

병렬화는 신중히 병렬화를 잘 못 사용하면 오히려 성능이 더 나빠질 수 있기 때문에 주의해서 사용해야 합니다. public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .filter(mersenne -> mersenne.isProbablePrime(50)) .limit(20) .forEach(System.out::println); } static Stream primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } 성능을 기대하고 paralle()을 호출하면 아무것도 출력하지 못합니다. 이는 스트림이 파이프라인을 ..

[Effective Java] Item47. 반환 타입으로는 스트림보다 컬렉션이 낫다

스트림 반복 Stream 인터페이스는 Iterable 인터페이스의 추상 메서드를 모두 포함하고 있고, 정의한 방식대로 동작하지만 Iterable 을 확장하지는 않았기 때문에 for-each로 반복할 수 없습니다. 만약 Stream을 반복문으로, 또는 그 반대로 사용하고 싶은 경우에는 중개해주는 어댑터를 사용합니다. Stream -> Iterable public static Iterable iterableOf(Stream stream){ return stream::iterator; } for (ProcessHandle p : iterableOf(ProcessHandle.allProcesses())) { // ... } Iterable -> Stream public static Iterable streamO..

[Effective Java] Item46. 스트림에서는 부작용 없는 함수를 사용하라

Map freq = new HashMap(); try(Stream words = new Scanner(file).tokens()) { words.forEach(word -> { freq.merge(word.toLowerCase(), 1L, Long::sum); }); } forEach 내부에서 외부 상태(freq)를 수정하므로 순수 함수가 아닙니다. Map freq; try(Stream words = new Scanner(file).tokens()) { freq = words.collect(groupingBy(String::toLowerCase, counting())); } Collector collect 메서드는 스트림 종료작업으로 Collector 타입의 인자를 받아서 처리합니다. java.util...

[Effective Java] Item45. 스트림은 주의해서 사용하라

스트림(Stream) API? 스트림 API는 다량의 데이터 처리 작업을 위해 JDK8부터 추가되었습니다. 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 의미하며, 스트림 파이프라인은 이 원소들로 수행하는 연산단계를 표현하는 개념입니다. 스트림 안의 데이터 원소들은 기본적으로 객체 참조타입이며, int, long, double의 세가지 기본타입을 지원하기도 합니다. 스트림 파이프라인 public static void main(String[] args) { List.of("apple", "banana", "car") // 리스트 .stream() // 소스 스트림 .filter(s -> s.startsWith("b")) // 중간 연산 .forEach(System.out::println); // 종단 연..

[Effective Java] Item 44. 표준 함수형 인터페이스를 사용하라

표준 함수형 인터페이스 java.util.function패키지에는 총 43개의 함수형 인터페이스를 제공합니다. 이 중 6개 정도만 기억하면 나머지도 유추하기 쉽습니다. UnaryOperator T apply(T t): 반환값과 인수의 타입이 같은 함수, 인수는 1개. String::toLowerCase BinaryOperator T apply(T t1, T t2): 반환값과 인수의 타입이 같은 함수, 인수는 2개. BigInteger::add Predicate boolean test(T t): 한 개의 인수를 받아서 boolean을 반환하는 함수. Collection::isEmpty Function R apply(T t): 인수와 반환 타입이 다른 함수. Arrays::asList Supplier T g..

[Effective Java] Item43. 람다보다는 메서드 참조를 사용하라

메서드 참조 List.of(1, 2, 3, 4).forEach(i -> System.out.println(i)); List.of(1, 2, 3, 4).forEach(System.out::println); // 메서드 참조 메서드 참조를 사용할 때 주의사항 대부분의 경우 람다에 비해 코드가 간결하고 명확해지지지만 람다에서 사용하는 매개변수 이름이 좋은 가이드가 된다면 코드가 더 길더라도 오히려 읽기가 더 쉬워질 것입니다. 또한, 메서드의 이름이 너무 길다면 오히려 람다가 더 간결해 질 수 있습니다. service.execute(() -> action()); service.execute(GoshThisClassNameIsHumongous::action); // 메서드 참조 메서드 참조의 유형 정적 메서드 참..

[Effective Java] Item42. 익명 클래스보다는 람다를 사용하라

람다의 장점 람다식은 메서드가 하는 일을 보다 간결하고 읽기 쉽게 표현합니다. 익명 클래스로 작성된 코드입니다. Collection.sort(words, new Comparator() { public int compare(String s1, String s2){ return Integer.compare(s1.length(), s2.length()); } }); 람다식으로 바꾸면 Collection.sort(words, (s1,s2) -> Integer.compare(s1.length(), s2.length())); 열거 타입에서의 람다 public enum Operation { PLUS("+") { public double apply(double x, double y) { return x + y; } }..

[Effective Java] Item41. 정의하려는 것이 타입이면 마커 인터페이스를 활용하라

마커 인터페이스 일반적인 인터페이스와 동일하지만 아무 메서드도 선언하지 않은 형태의 인터페이스입니다. 자신을 구현하는 클래스가 특정 속성을 가짐을 표시하기 위해 사용합니다. 대표적인 마커 인터페이스로는 Serializable, Cloneable 등이 있습니다. 마커 애너테이션과의 비교 마커 인터페이스의 장점 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 사용할 수 있습니다. ObjectOutputSteam.writeObject메서드의 경우 Serializable을 구현하지 않은 경우 NotSerializableException예외를 발생시킵니다. 마커 애너테이션도 Java Reflection을 이용하여 같은 기능을 할 수 있습니다. @MySerializable public clas..