반응형

문제 링크

 

11286번: 절댓값 힙

첫째 줄에 연산의 개수 N(1≤N≤100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 0이 아니라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0

www.acmicpc.net

 

풀이 ) 우선순위큐

문제 조건에 따라 우선순위큐에 넣었다가 빼주면된다.

뺄 때 조건은 절댓값이 같을 때는 작은값 즉 음수를 꺼내고, 절댓값이 다를때는 절댓값이 작은값을 꺼내주면 된다.

 

import java.io.*;
import java.util.PriorityQueue;

public class Main {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder answer = new StringBuilder();

        int n = Integer.parseInt(br.readLine());

        PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2)->{
            if(Math.abs(o1) == Math.abs(o2)) {
                return o1-o2;
            } else {
                return Math.abs(o1)-Math.abs(o2);
            }
        });
        while(n-- > 0) {
            int x = Integer.parseInt(br.readLine());

            if(x == 0) {
                if(pq.isEmpty()) {
                    answer.append(0).append('\n');
                } else {
                    answer.append(pq.poll()).append('\n');
                }
            } else {
                pq.offer(x);
            }
        }

        System.out.println(answer.toString());
    }
}
반응형
반응형

2장 객체 생성과 파괴

 

아이템 6. 불필요한 객체 생성을 피하라

 

  • 생성자 대신 정적 팩토리 메서드를 사용해 불필요한 객체 생성 회피 가능

    Boolean(String);			// java 9에서 사장
    
    Boolean.valueOf(String);
    
  • 캐싱하여 재사용을 통해 성능 개선

    static boolean isRomanNumeral(String s) {
        return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"
                        + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$")
    }
    
    public class RomanNumerals {
        
        private static final Pattern ROMAN = Pattern.compile(
            "^(?=.)M*(C[MD]|D?C{0,3})"
            + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"
        );
        
        static boolean isRomanNumeral(String s) {
            return ROMAN.matcher(s).matchers();
        }
    }
    

    의도치 않은 오토박싱 회피

 

TODO

  • 정규표현식
  • 유한 상태 머신
  • 지연 초기화
  • 어댑터 : 실제 작업은 뒷단 객체에 위임하고, 자신은 제2의 인터페이스 역할을 해주는 객체
  • 방어적 복사
반응형

'Java > OOP' 카테고리의 다른 글

[Effective Java] 2장. 아이템5  (0) 2022.07.17
[Effective Java] 2장. 아이템4  (0) 2022.07.16
[Effective Java] 2장. 아이템3  (0) 2022.07.16
[Effective Java] 2장. 아이템2  (0) 2022.07.15
[Effective Java] 2장. 아이템1  (0) 2022.07.14
반응형

2장 객체 생성과 파괴

 

아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

 

사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않음

 

의존 객체 주입 패턴

인스턴스 생성 시 생성자에 필요한 자원을 넘겨주는 방식

 

예시

public class SpellChecker {
    
    private final Lexicon dictionary;
    
    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }
}

 

특징

  • 장점

    • 유연성
    • 테스트 용이성 개선
  • 단점

    • 큰 프로젝트에서 프로젝트를 어지럽게 만듦 => 의존 객체 주입 프레임워크 사용

 

TODO

  • 한정적 와일드카드 타입
반응형

'Java > OOP' 카테고리의 다른 글

[Effective Java] 2장. 아이템6  (0) 2022.07.18
[Effective Java] 2장. 아이템4  (0) 2022.07.16
[Effective Java] 2장. 아이템3  (0) 2022.07.16
[Effective Java] 2장. 아이템2  (0) 2022.07.15
[Effective Java] 2장. 아이템1  (0) 2022.07.14
반응형

2장 객체 생성과 파괴

 

아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라

 

추상 클래스 한계

  • 하위 클래스를 만들어 인스턴스화 가능

 

private 생성자 장점

  • 인스턴스화 방지
  • 상속 불가

 

예시

public class UtilityClass {
    
    // 기본 생성자 생성 방지(인스턴스화 방지용)
    private UtilityClass() {
        throw new AssertionError();
    }
}

 

반응형

'Java > OOP' 카테고리의 다른 글

[Effective Java] 2장. 아이템6  (0) 2022.07.18
[Effective Java] 2장. 아이템5  (0) 2022.07.17
[Effective Java] 2장. 아이템3  (0) 2022.07.16
[Effective Java] 2장. 아이템2  (0) 2022.07.15
[Effective Java] 2장. 아이템1  (0) 2022.07.14
반응형

2장 객체 생성과 파괴

 

아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라

 

싱글턴

인스턴스를 오직 하나만 생성할 수 있는 클래스

 

방식

  1. public static final 필드 방식

    public class Elvis {
        
        public static final Elvis INSTANCE = new Elvis();
        private Elvis() { ... }
    }
    
    • 장점

      • 싱글턴임이 API에 명백히 드러남
      • 간결함
    • 단점

      • 리플렉션 API AccessibleObject.setAccessible( )을 사용해 private 생성자 호출 가능
      • 직렬화 시 모든 인스턴스 필드를 transient이라 선언하고, readResolve( )를 제공해야 함 (하지 않는 경우 역직렬화 시 새로운 인스턴스 생성)
  2. 정적 팩토리 방식

    public class Elvis {
        
        private static final Elvis INSTANCE = new Elvis();
        private Elvis() { ... }
        public static Elvis getInstance() {
            return INSTANCE;
        }
    }
    
    • 장점

      • API를 바꾸지 않고 싱글턴이 아니게 변경 가능
      • 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다.
      • 정적 팩토리의 메서드 참조를 supplier로 사용 가능
    • 단점

      • 리플렉션 API AccessibleObject.setAccessible( )을 사용해 private 생성자 호출 가능
      • 직렬화 시 모든 인스턴스 필드를 transient이라 선언하고, readResolve( )를 제공해야 함 (하지 않는 경우 역직렬화 시 새로운 인스턴스 생성)
  3. 열거 타입 방식

    public enum Elvis {
        
        INSTANCE;
    }
    
    • 장점

      • 직렬화 상황이나 리플렉션 공격에서도 제2의 인스턴스 생성 방지
    • 단점

      • Enum 외의 클래스 상속 시 사용 불가

 

TODO

  • API를 바꾸지 않고 싱글턴이 아니게 변경
  • 제네릭 싱글턴 팩토리
  • Serializable.readResolve()
반응형

'Java > OOP' 카테고리의 다른 글

[Effective Java] 2장. 아이템6  (0) 2022.07.18
[Effective Java] 2장. 아이템5  (0) 2022.07.17
[Effective Java] 2장. 아이템4  (0) 2022.07.16
[Effective Java] 2장. 아이템2  (0) 2022.07.15
[Effective Java] 2장. 아이템1  (0) 2022.07.14
반응형

2장 객체 생성과 파괴

 

아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라

 

선택 매개변수가 많은 경우 대안

  1. 점층적 생성자 패턴

    public class NutritionFacts {
        
        private final int servingSize;	// 필수
        private final int servings;		// 필수
        private final int calories;		// 선택
        private final int fat;			// 선택
        private final int sodium;		// 선택
        
        public NutritionFacts(int servingSize, int servings) {
            this(servingSize, servings, 0);
        }
        
        public NutritionFacts(int servingSize, int servings, int calories) {
            this(servingSize, servings, calories, 0);
        }
        
        public NutritionFacts(int servingSize, int servings, int calroies, int fat) {
            this(servingSize, servings, calories, fat, 0);
        }
        
        public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
            this.servingSize 	= servingSize;
            this.servings 		= servings;
            this.calories		= calories;
            this.fat 			= fat;
            this.sodium			= sodium;
        }
    }
    
    • 필수 매개변수만 받는 생성자를 만들고 선택 매개변수를 받는 생성자를 늘려가는 방식

    • 단점

      • 매개변수 개수가 많아지면서 클라이언트 코드를 작성하거나 읽기 어려움.
  2. 자바빈즈 패턴

    NutritionFacts cocaCola = new NutritionFacts();
    cocaCola.setServingSize(240);
    cocaCola.setServings(8);
    cocaCola.setCalories(100);
    cocaCola.setSodium(35);
    
    • 매개변수가 없는 생성자로 객체를 만든 후, setter 메서드를 호출하여 값 설정

    • 단점

      • 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되기 전까지 일관성이 무너진 상태
      • 클래스를 불변으로 만들 수 없음
  3. 빌더 패턴

    public class NutritionFacts {
        
        private final int servingSize;	// 필수
        private final int servings;		// 필수
        private final int calories;		// 선택
        private final int fat;			// 선택
        private final int sodium;		// 선택
        
        public static class Builder {
            
            private final int servingSize;	// 필수
            private final int servings;		// 필수
    
            private final int calories;		// 선택
            private final int fat;			// 선택
            private final int sodium;		// 선택
    
            public Builder(int servingSize, int servings) {
                this.servingSize 	= servingSize;
                this.servings 		= servings;
            }
            
            public Builder calories(int val) {
                calories = val;
                return this;
            }
            
            public Builder fat(int val) {
                fat = val;
                return this;
            }
    
            public Builder sodium(int val) {
                sodium = val;
                return this;
            }
    
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
        
        private NutritionFacts(Builder builder) {
            this.servingSize 	= builder.servingSize;
            this.servings 		= builder.servings;
            this.calories		= builder.calories;
            this.fat 			= builder.fat;
            this.sodium			= builder.sodium;
        }
        
    }
    
    • 필수 매개변수만으로 빌더 객체를 생성하고, 선택 매개변수 값을 설정한 후 build 메서드 호출

    • 생성할 클래스 안에 정적 멤버 클래스로 만듦.

    • 메서드 연쇄 방식 : 클래스 자신을 반환하는 메서드를 연쇄적으로 호출

    • 장점

      • 읽고 쓰기 쉬움 ( named optional parameters 방식과 유사 )

      • 계층적으로 설계된 클래스와 함께 쓰기 좋음

        public abstract class Pizza {
            
            public enum Topping {
                HAM, MUSHROOM, ONION, PEPPER, SAUUSAGE
            }
            final Set<Topping> Toppings;
            
            abstract static class Builder<T extends Builder<T>> {
                
                EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
                public T addTopping(Topping topping) {
                    toppings.add(Objects.requireNonNull(topping));
                    return self();
                }
                
                abstract Pizza build();
                
                protected abstract T self();
            }
            
            Pizza(Builder<?> builder) {
                toppings = builder.toppings.clone();
            }
            
        }
        
        public calass NyPizza extends Pizza {
            
            public enum Size { SMALL, MEDIUM, LARGE }
            private final Size size;
            
            public static class Builder extends Pizza.Builder<Builder> {
                
                private final Size size;
                
                public Builder(Size size) {
                    this.size = Objects.requireNonNull(size);
                }
                
                @Override
               	public NyPizza build() {
                    return new NyPizza(this);
                }
                
                @Override
                protected Builder self() {
                    return this;
                }
            }
            
            private NyPizza(Builder builder) {
                super(builder);
                size = builder.size;
            }
        }
        
        public class Calzone extends Pizza {
            
            private final boolean sauceInside;
            
            public static class Builder extends Pizza.Builder<Builder> {
                
                private boolean sauceInside = false;
                
                public Builder sauceInside() {
                    this.sauceInside = true;
                }
                
                @Override
                public Calzone build() {
                    return new Calzone(this);
                }
                
                @Override protected Builder self() {
                    return this;
                }
            }
            
            private Calzone(Builder builder) {
                super(builder);
                this.sauceInside = builder.sauceInside;
            }
        }
        
      • 가변인수 매개변수를 여러 개 사용 가능

    • 단점

      • 빌더 구현 => Lombok

 

정리

생성자나 정적 팩토리가 처리해야 할 매개변수가 많다면 빌더 패턴 선택

 

용어

공변 반환 타이핑 ( covariant return typing) : 하위 클래스의 메서드가 상위 클래스의 메서드가 정의한 반환 타입이 아닌 하위 타입을 반환하는 기능

반응형

'Java > OOP' 카테고리의 다른 글

[Effective Java] 2장. 아이템6  (0) 2022.07.18
[Effective Java] 2장. 아이템5  (0) 2022.07.17
[Effective Java] 2장. 아이템4  (0) 2022.07.16
[Effective Java] 2장. 아이템3  (0) 2022.07.16
[Effective Java] 2장. 아이템1  (0) 2022.07.14

+ Recent posts