본문 바로가기

ALL

(128)
9. 환경변수와 빌드인수 환경변수와 빌드인수 > docker build --build-arg > docker run --env 도커 이미지 빌드는 Dockerfile에 따라서 이루어지고, 도커 컨테이너의 실행은 도커 이미지에 따라서 이루어진다. 그런데 상황에따른 약간의 유연함은 항상 필요하다. 같은 Dockerffile로 빌드하더라도 상황에 맞게 일부 빌드 내용을 바꾸거나, 같은 이미지로 컨테이너를 실행하더라도 일부 설정을 다르게 해야할 수 있다. 이때 사용할 수 있는것이 환경변수와 빌드인수이다. 환경변수 // server.js ... app.listen(80); ... 위 코드는 nodejs로 작성된 웹서버이다. 마지막에 app.listen(80) 코드를 통해 80번 포트로 요청을 받아서 동작한다는 것을 알 수 있다. 이 소스..
5-7) 타입 안전 이종 컨테이너를 고려하라 타입 안전 이종 컨테이너 public class Favorites { public void putFavorite(Class type, T instance); public T getFavorite(Class type); } 제네릭은 Set, Map 등 단일원소 컨테이너에 흔히 쓰인다. 이러한 컨테이너는 원소로 넣을 수 있는 타입의 수가 제한되어 있기 때문에 매개변수 타입의 수가 제한되어 있다. 하지만 더욱 유연한 컨테이너가 필요할 때도 있다. 다양한 타입의 원소를 가지는 컨테이너가 필요하다면 어떨까? 다양한 타입을 가지면서도 값을 넣거나 뺄 때 안전하게 사용할 수 있어야 할 것이다. 그리고 이를 타입 안전 이종 컨테이너라고 부른다. 위의 Favorites 클래스는 각 타입마다 좋아하는 객체를 넣을수 있는 ..
5-6) 제네릭과 가변인수를 함께 쓸 때는 신중하라 제네릭과 가변인수 // 제네릭과 가변인수를 함께 사용하면 컴파일러가 경고를 보낸다 // Type safety: Potential heap pollution via varargs parameter stringList public static void myFunc(List... stringLists) List intList = List.of(1); Object[] objects = stringLists; objects[0] = intList; // 힙 오염 발생 String s = stringLists[0].get(0); // ClassCastException 런타임 에러 발생 } 가변인수와 제네릭은 자바5때 함께 추가되었으나 함께 사용하기에는 까다롭다. 제네릭과 가변인수를 함게 사용하면 컴파일러는 힙 오염..
5-5) 한정적 와일드카드를 사용해 유연성을 높혀라 매개변수화 타입의 불공변성 // Integer 타입은 Number 타입을 상속했기때문에, num = intNum가 가능하다. Number num = 1; Integer intNum = 1; num = intNum; // Integer 타입은 Number 타입을 상속했지만, 매개변수 타입으로 전달되었을때는 그 관계가 유지되지 않는다. // 따라서 numStack = intStack 코드는 컴파일 에러가 발생한다. Stack numStack = new Stack(); Stack intStack = new Stack(); numStack = intStack; 매개변수화 타입은 불공변이다. 불공변이라는 말은 타입의 관계가 같이 변하지 않는다는 것을 말한다. 위의 코드를 보면 Integer 타입은 Number 타..
5-5) 이왕이면 제네릭 메소드로 만들어라 raw 타입을 사용한 메소드 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } 두개의 Set를 받아서 하나로 합친 후 반환하는 union 클래스가 있다. 제네릭 없이 raw타입만을 매개변수로 받고 raw 타입으로 반환하기 때문에, 서로 다른 타입 매개변수를 가지고있는 Set 객체라고해도 일단 하나로 합쳐진다. 그리고 반환된 Set는 Object 타입을 가지고 있다고 나오는데, 실제로 어떤 타입을 가지고 있는지는 알수가 없다. 즉 매우 위험한 코드이다. Set intSet = new HashSet(); intSet.add(1); Set strSet = new Has..
5-4) 이왕이면 제네릭 타입으로 만들라 Object 기반 Stack public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { this.elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { this.ensureCapacity(); this.elements[this.size++] = e; } public Object pop() { if(this.size == 0) { throw new EmptyStackException(); } Object result = thi..
5-3) 배열보다는 리스트를 사용하라 배열과 제네릭의 차이 // 컴파일 에러가 발생하지 않는다. Object[] objectArray = new String[1]; // 컴파일 에러가 발생한다. List objectList = new ArrayList() 배열에서는 Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위타입이 된다. 리스트에서는 List가 List의 하위타입이 아니다. 따라서 위의 코드를 보면 배열에서는 가능한 코드가 리스트에서는 컴파일 에러가 발생한다. 배열이 더 유연한 코드를 제공하는거 같지만 실제로는 위험한 코드를 허용해주는 것이다. 배열의 저러한 특성때문에 아래의 코드같이 런타임에 문제가 생길 수 있다. // 런타임에서 발생 Object[] objectArray = new String[1]; objec..
5-2) 비검사 경고를 제거하라 비검사 경고 //비검사 형변환 경고 발생 Set nameSet = new HashSet(); //타입 매개변수를 명시하여 비검사 형변환 경고 제거 Set nameSet = new HashSet(); 제네릭을 사용하기 시작하면 많은 컴파일러 경고를 보게 될 것이다. 위의 코드에서는 보면 Set타입의 변수에 HashSet 객체를 넣으려고 하자 비검사 형변환 경고가 발생했다. HashSet에 타입 파라미터가 없으므로 어떤 타입이 들어갈 지 알 수 없으므로, 런타임에 형변환 문제가 발생 할 수 있다는걸 경고한 것이다. 이는 실제로 위험한 코드이기 때문에 타입 파라미터를 명시하여 비검사 형변환 경고를 제거해주어야 한다. @SuppressWarnings @SuppressWarnings("unchecked") pub..