[Codesquad] CS10 - 220104 그룹 리뷰 후기 및 정리

5197 단어 코드스쿼드TILTIL

오늘 처음으로 같은 그룹원들과 코드 리뷰를 진행했다.
아마도 코드스쿼드를 하면서 가장 크게 배워야할 점은 역시 내 코드를 소개하고 리뷰하는 습관인 것 같다.
노력해봐도 내 생각의 흐름이나 질문하는 것은 어렵다.
시간이 지나면서 늘기를 바라며 코드를 짤 때부터 흐름을 정리해보는 것도 해봐야겠다.

크게 리뷰하면서 얻은 꿀팁이나 새로 정리한 내용들을 적어보려고 한다.

GIST 관련 프로젝트 관리 팁

  • GIST clone
    • 주로 프로젝트 제출에 쓰이는 GIST는 폴더 구조를 지원하지 않는다. java는 src 내에 코드가 들어가있어서 프로젝트 통째로 push가 불가능해서 이번에는 그냥 수동으로 file을 업로드했다.
    • 그런데 그룹원들의 관리방법에서 좋은 방법들을 많이 얻었다.
      • 먼저, 그냥 GIST를 clone한 폴더에 java file을 만드는 방법이다. 굳이 java project로 만들지 않더라도 IDE에서 classpath를 설정하여 컴파일이 가능하다고 한다.
      • 다른 방법은 src 폴더 내에 clone하여 관리하는 방식이다. 이 때, clone한 폴더의 이름이 gist 특성상 의문의 코드 형식인데 아래와 같이 명령어를 사용하면 깔끔하게 불러올 수 있다.
        git clone <url> .
        git clone <url> <새로 만들 폴더명>
      • 또한, github에 기록을 남기기 위해서 github에는 push, gist에는 수동으로 파일을 업로드했었는데 그냥 remote를 두개 설정하면 된다. 나중에는 gist를 clone한다음 gist와 github에 각각 remote를 설정해서 관리하려고 한다.

테스트 코드 관련 팁

그룹원 중 쿠킴이 테스트 코드에 대한 지식을 공유해주셨다. 예전에 [스프링 부트와 AWS로 혼자 구현하는 웹 서비스]를 읽을 때 테스트 코드를 접하긴 했지만 여전히 print를 통해 확인하고 있었다. 그러다 테스트 코드로 검증하는 것이 좋아보여서 이번 기회부터 적극적으로 사용해보려고 한다.

책과 마찬가지로 junit을 사용해서 테스트를 진행하였고 이 때 커버리지라는 개념도 배웠다. 예전에 github repository에 action 등으로 자동으로 테스트를 해서 coverage를 띄워주는 걸 본적이 있는데 아마 유사한 개념같다. 테스트 관련해서도 책이나 검색을 통해서 좀 배워봐야겠다.

java의 Arraylist에는 왜 integer가 아닌 Integer를 써야 할까?

어제 미션을 구현하면서 가변 크기의 배열을 쓰기 위해서 Arraylist를 사용했다. 그런데 Arraylist에는 우리가 흔히 사용하는 boolean, integer와 같은 primitive type이 아닌 Boolean, Integer와 같은 reference type을 사용해야 한다.

그럼 도대체 primitive type과 reference type은 무엇일까?

급하게 arraylist를 쓰기 전에 검색했을 때는 NULL을 담을 수 있냐, 없냐가 가장 큰 차이라는 말을 많이 보았다. 그래서 찾아보기 전에 다음과 같이 추론했다.

  • Arraylist는 선언 시에 크기를 정하지 않아도 되기 때문에 초기에는 일정 크기의 NULL이 담겨 있을텐데, primitive type은 NULL을 담을 수 없기 때문에 그런게 아닐까?

정확한 이유를 알기 위해 찾아보았다.
자바 기본서인 [자바의 정석]에는 이렇게 나와있다.

  • 기본형 변수도 어쩔 수 없이 객체로 다뤄야 하는 경우가 있다. 예를 들면, 매개변수로 객체를 요구할 때, 기본형 값이 아닌 객체로 저장해야할 때, 객체 간의 비교가 필요할 때 등등의 경우에 기본형 값들을 객체로 변환한 wrapper 클래스를 사용한다.

대충 wrapper class란 기본형 데이터를 객체로 만들어 주기 위한 wrap인 것이다.
(이 과정을 Boxing이라 하고, 역은 Unboxing이다)

설명이 조금 부족해서 더 찾아보았다.

왜 우리는 Arraylist에서 wrapper class를 써야 하나요?
stackoverflow에 있는 이 글이 질문을 관통하는 글인 것 같다.
ArrayList는 제네릭을 통해 구현되어 있다. 당연하게도 ArrayList는 사용자에 따라 어떤 객체가 담길지가 달라지기 때문이다.
즉, ArrayList는 object class의 하위 클래스들을 담을 수 있도록 제네릭으로 구현되어 있다.
이 때, primitive type의 자료형은 객체가 아니기 때문에 당연히 사용할 수 없는 것이다.
(이 때문에 java가 완전한 객체지향이 아니라고 불린다고 한다.)

결국, integer와 Integer의 차이는 객체냐 아니냐, 이게 다인 것이다.
위에서 말한 NULL 문제도 아래 stackoverflow에 명쾌하게 설명되어있다.

왜 기본 자료형은 null일 수 없나요?

예전에 C++ 공부할 때 공부한 포인터개념으로 이해하면 될 것 같다. 객체 자료형은 결국 포인터고, 결국 객체는 어떤 value를 가리키는 주소이다. NULL은 어떤 포인터가 어떤 메모리 주소도 참조하지 않은 상태이다. 그런데 기본 자료형은 그냥 값 자체이다. 그렇기 때문에 NULL이 아니라 그냥 기본 값을 가지고 초기화된다. 이해한 게 맞는지 모르겠지만 대충 감이 온다.

그럼 왜 java는 기본 자료형을 객체로 만들지 않았을까?

객체 자료형을 이용해야 할 때는 wrapper class를 사용해야 하는 불편함이 있지만, 일반적으로 자주 사용되는 자료구조이기 때문에 성능 저하를 막기 위해서!

Java에서 문자열에 특정 위치에 글자를 삽입하려면 어떻게 해야 할까?

2진수를 16진수로 변경하는 문제를 풀 때, 2진수는 작은 비트부터 왼쪽으로 만들어두어서 16진수로 변경해서 출력하려면 반대로 뒤집어야 했다. 파이썬에서는 문자열을 뒤집는게 쉬운 일이지만 java로 찾아보니 굉장히 귀찮아보였다. 그래서 그냥 insert로 특정 위치에만 계속 넣는 식으로 구현하려고 했더니 String 객체에서는 이를 지원하지 않았다.

StringBuffer 클래스 관련 출처

그래서 찾은 것은 StringBuffer 클래스이다. 해당 클래스에서는 insert 함수를 지원한다.
그래서 특정 index에 문자열을 삽입할 수 있었다. String이든 char든 obj의 값이든 모두 가능하게 되어있다.

  • StringBuffer 클래스의 비교
    • 그래서 만든 16진수 변환기를 테스트하려고 하니 문자열끼리 비교가 되어서 주소값이 다르다고 fail이 떴다.
    • 그래서 String을 비교할 때 사용하는 equals()를 사용하려고 했다.
    • 근데 StringBuffer는 equals 사용 시 비교연산자를 사용하여 원하는 결과를 얻을 수 없었다.
      • 어쩔 수 없이 toString()을 사용하여 StringBuffer를 String으로 변환하여 eqauls()로 테스트하였다.
  • StringBuilder 클래스
    • StringBuffer와 유사한 StringBuilder가 있다. 이 두 클래스는 대부분의 기능을 모두 공유한다.
      (삽입, 삭제, 추출 등)
    • 가장 큰 차이점은 동기화의 유무이다. StringBuffer는 멀티쓰레드 환경에 대비하여 동기화 처리가 되어 있고, Builder는 동기화 처리가 되어 있지 않아서 싱글쓰레드에서는 성능에 유리할 것이다.

그건 그렇고, 문자열 뒤집으려면 어떻게 해야 할까?

python이라면 string[::-1] 로 해결되겠지만 ... java에선 어떻게 해야 할까?

  • StringBuffer 클래스의 reverse()를 사용한다.

역시나 StringBuffer의 도움을 받으면 된다. 필요하면 다시 toString으로 변환하면 되니까!

오늘도 꽤나 많은 것을 배웠다. 이런 식으로 사소한 것 하나도 계속 조사해보면서 기록해둬야겠다.
대충 아는 내용이라고 넘어가지 말기!

좋은 웹페이지 즐겨찾기