java를 사용하면서 느낀 단점들

프로그래밍에 손을 대면서 거의 2~3년간 주력으로 C,C++만을 사용했다가 이번에 처음으로 3개월간 OOP를 배우면서 자바를 한동안 쓸일이 생겼었다. 순수하게 짠코드만 대략 3천~4천줄정도될텐데 자바를 쓰면서 느낀것을 한번 풀어보려고 한다. 거의 자바내의 기본문법만을 사용했다.

  1. 지나치게 많은 지원 메소드와 의미없는 추상 자료구조

cpp stack image

java Stack

image image image image image

아마 Stack 내부적으로 ArrayList를 자료구조로 사용하면서 기존 ArrayList의 메소드를 그대로 받아서 사용할 수 있게 되어있는것 같다.작동상 중복되는 메소드가 너무너무 많다. CPP의 stack도 내부적으로 deque를 자료구조로 사용하지만 deque의 메소드를 외부로 노출시키지 않았다. 자바에서는 Stack을 사용함으로 이 자료구조는 “stack구조로만 돌아”라고 보장을 못하는 코드가 되어버렸다.

  1. 지원 자료구조의 배열선언 불가 코드를 짜다가 2차원 배열에 각 원소가 리스트로 이루어져있는 자료형를 만들일이 있었다 n이 정적이아니라서 C스타일 배열로는 만들수없고 동적할당으로 해결해야한다.
    1
    2
    3
    4
    5
    6
    7
    8
    
    vector<int>** a = new vector<int>*[b];
    for (int i = 0; i < b; i++) {
     a[i] = new vector<int>[c];
    }
    for (int i = 0; i < b; i++) {
     delete[] a[i];
    }
    delete[] a;
    

    물론 이렇게 할시에 메모리 해제가 귀찮아진다. 그냥 3차원 벡터를 만들어버리면 가장 간단하게 해결할 수 있다.

    1
    2
    3
    4
    5
    
    vector<vector<vector<int>>> a;
    a.resize(b);
    for (int i = 0; i < b; i++) {
     a[i].resize(c);
    }
    

자바에서는 제네릭을 배열로 선언이 안된다고 하더라

1
2
3
4
5
6
7
8
9
a = new HashMap<>();
for (int y = 0; y < height; y++) {
    HashMap<Integer, LinkedList<Integer>> hashMap = new HashMap<>();
    for (int x = 0; x < width; x++) {
        LinkedList<Integer> list = new LinkedList<>();
        hashMap.put(x, list);
    }
    a.put(y, hashMap);
}

이런식으로 해쉬맵을 엮어서 배열로 만들든.. LinkedList를 상속 받는 클래스 하나를 만든다면 얘에 대해서는 동적 배열로 선언을 해도 상관이 없다더라.

1
2
3
public class A extends LinkedList<Integer> {
}
A[][] a = new A[a][b];
  1. 패키지내 접근이 가능한 protected :상속 관계에서 캡슐화 보장을 못하게 되었다. Cpp의 friend를 안해도 된다는 장점이 생겼지만

  2. 애매한 final : const가 아닌 final은 애매하다. 일반 변수들은 멤버 변수를 final로 할시에는 변경이 불가능하지만 레퍼런스로 움직이는 클래스들은 그대로 list에 값을 추가한다던가 내부를 변화 시킬수있다.

    1
    2
    
    const verctor<int> a;
    vector<int> const a;
    

    뒤에 const를 붙이는 방식으로 굴러간다.

이게 어떻게 스노우볼이 굴러가냐면

1
a.getUsers().add(i);

이런 게터를 통해서 외부에서 값변경이 되버린다. 물론 이거를 복사를 해서 getter를 반환하는 방법이 있겠지만 메모리 할당 + 복사까지 비용을 생각하면 또 신경쓰이는 부분이 되며 이 반환된 값조차 변경이 되기에 이 지금 반하고 사용하는 값이 class의 고유 값으로서 보존된다고 언어에서 보장하지 못한다. 자바만 쓰던 사람이 getter를 const로 반환하는 일반적인 코드베이스인 언어를 쓴다면 경우 로직을 강제로 바꾸게 되는 일이 생길거다.

이 모든 건 자기가 혼자 모든 코드를 짜고 책임을 지면 전혀 상관없는 얘기일지도 모른다 오히려 자유도가 높아서 좀더 자유롭게 코드를 짤 수 있다고 생각할지도 모른다. 하지만 내가 생각하는 이 문제점들은 일반적인 사람의 허용범위를 넘어선 행동을 가능하게하고 이는 나 또는 남들이 일반적인 사람들이 생각하는 코드의 흐름을 “ 클래스는 class 밖의 코드에서 내부 변수를 바꾸는 로직이 없을거야” 깬 코드를 짜고 나중에 디버깅을 힘들게 할 수 있다.

Posted 2020-07-27