데브코스 001일차 학습일지: 자바 이야기

rescogitans·2022년 3월 23일
0

프레임워크를 위한 자바

자바 이야기

개발 환경

  • JVM: 자바가 실행되기 위해서 필요: 자바 실행 환경(JRE) -> java 명령어만, 버추얼 머신만 있는 경우

  • JRE + 개발툴 -> 개발 환경: JDK -> java + javac명령어까지

  • 역사

    • 썬 마이크로시스템즈에서 개발
    • 오라클에서 썬 인수
    • 오라클에서는 일부 유료화
    • OpenJDK
  • 콘솔 창에

    • java --versionjavac --version을 터미널에 입력하여 설치 여부/버전을 확인한다.
  • 명령어 관하여

    • 컴파일: javac ClassName.java
    • 실행: java ClassName
      • Error: Could not find or load main class 클래스 경로를 확인하지 못 해서 발생한 문제임
        • 환경 변수 편집으로 해결 가능
          • ;.을 환경 변수 마지막에 넣어주면, 추가적으로 현재 확인하고 있는 경로에서도 클래스 파일을 찾는다.

빌드 툴(Build Tool)

  • 일일히 자바 파일을 컴파일하는 귀찮다. -> 빌드를 자동화하자: 빌드 툴의 등장

  • 자바의 빌드 툴

    • Ant: 과거에 많이 사용한다.
    • Maven: 자바에 특화되어 있다.
    • Gradle: 메이븐보다 더 간결한 문법을 제공한다.
    • 현재는 Maven, Gradle 많이 사용하며 Maven -> Gradle로 옮겨가는 추세이다.
  • Gradle 직접 설치해보기

    • 설치 페이지 따라서 파일설치, 압축 해제, 환경변수 설정
    • gradle --version을 터미널에 입력하여 설치 여부 확인
  • Gradle 사용해보기

    • 프로젝트 생성: gradle init명령어

      • 빌드 스크립트 언어 선택
        • 그루비, 코틀린
        • 초기에는 그루비만 있었다가, 코틀린이 추가되었음
        • 코틀린 사용량이 증가하는 추세
        • 그루비는 레퍼런스가 많음
    • 프로젝트 구조: tree 명령어 이용해서 보면

      ├─.gradle
      ├─app
      │  └─src
      │      ├─main
      │      │  ├─java
      │      │  │  └─com
      │      │  │      └─programmers
      │      │  │          └─java
      │      │  └─resources
      │      └─test
      │          ├─java
      │          │  └─com
      │          │      └─programmers
      │          │          └─java
      │          └─resources
      └─gradle
          └─wrapper
      • 구조를 확인 가능
      • build.gradle 빌드 스크립트이다.
        • 소스 위치, 컴파일, 실행 방법 등이 기록되어 있다.
    • Task명령어

      • gradle build, gradle run

      • build.gradletasks.named("test") 형태로 작업이 명시되어 있다.

        • 예를 들어, gradle test를 실행하면 위의 taskstest라 명명된 작업이 실행된다.
      • 그런데, build. run의 경우는 위와 같은 task 설명이 없다.

        자바 프로젝트에서 공통적으로 많이 쓰이는 부분들의 taskset은 이미 규정되어 있다.

        -> plugin

      • gradle tasks명령어로 종류 확인 가능

      ------------------------------------------------------------
      Tasks runnable from root project 'HelloWorld'
      ------------------------------------------------------------
      
      Application tasks
      -----------------
      run - Runs this project as a JVM application
      
      Build tasks
      -----------
      assemble - Assembles the outputs of this project.
      build - Assembles and tests this project.
      buildDependents - Assembles and tests this project and all projects that depend on it.
      buildNeeded - Assembles and tests this project and all projects it depends on.
      classes - Assembles main classes.
      clean - Deletes the build directory.
      jar - Assembles a jar archive containing the main classes.
      testClasses - Assembles test classes.
      
      Build Setup tasks
      -----------------
      init - Initializes a new Gradle build.
      wrapper - Generates Gradle wrapper files.
      
      Distribution tasks
      ------------------
      assembleDist - Assembles the main distributions
      distTar - Bundles the project as a distribution.
      distZip - Bundles the project as a distribution.
      installDist - Installs the project as a distribution as-is.
      
      Documentation tasks
      -------------------
      javadoc - Generates Javadoc API documentation for the main source code.
      
      Help tasks
      ----------
      buildEnvironment - Displays all buildscript dependencies declared in root project 'HelloWorld'.
      dependencies - Displays all dependencies declared in root project 'HelloWorld'.
      dependencyInsight - Displays the insight into a specific dependency in root project 'HelloWorld'.
      help - Displays a help message.
      javaToolchains - Displays the detected java toolchains.
      outgoingVariants - Displays the outgoing variants of root project 'HelloWorld'.
      projects - Displays the sub-projects of root project 'HelloWorld'.
      properties - Displays the properties of root project 'HelloWorld'.
      tasks - Displays the tasks runnable from root project 'HelloWorld' (some of the displayed tasks may belong to subprojects).
      
      Verification tasks
      ------------------
      check - Runs all checks.
      test - Runs the test suite.
      • gradle tasks extension 설치하여 간편하게 확인, 실행 가능하다.

통합 개발 환경

  • VS Code(코드편집용)와 gradle, 그리고 extension들을 이용해도 일일히 각각을 실행해 줘야 하는 불편함이 있다.

    -> 통합 개발 환경(IDE; Integrated Development Environment)이 필요한 까닭

  • 자바 개발자들이 주로 사용하는 IDE

    • Eclipse: 과거 많이 쓰였으나, InteliJ 등장 이후 사용량 많이 줄어듬
    • InteliJ: 대세
  • IDE는 생산성을 증대시켜준다.

  • 단축키를 적절히 사용하면 생산성이 더 증가한다.

초보개발자가 알면 좋을 정보

Coding Convention

  • 팀, 회사, 개발 그룹에서 정해서 사용
  • 정하지 않은 경우 일반적인 자바 코딩 규칙을 따름
  • 카멜케이스
    • 클래스명은 대문자
    • 메서드, 변수명은 소문자
  • Indent: 들여쓰기
    • Tab, Space
    • 섞어 쓰면 안 된다!

Reference

  • 자바를 쓴다고 해서 포인터를 몰라서는 안 된다!

    • 자바에는 포인터 대신 레퍼런스라는 개념이 있다.
    • 자바에서는 alloc/free를 개발자가 신경 쓰지 않아도 될 뿐이다.
  • 자바의 primitive value를 제외한 모든 것은 reference value다!

    • primitive: boolean, byte, int, short, long, float, double, char

    • int a =100일 때, a를 전달 -> 값을 전달

    • Integer b = 100일 때, b를 전달 -> b의 레퍼런스를 전달

    • Call by value / Call by reference

    • array는 reference처럼 취급한다.

      • primitive value를 사용한 array라도 reference 취급한다!
      • 예시) int[], boolean[]

String

문자열의 비교

  • 문자열을 만드는 방법

    • String 클래스의 생성자를 사용해서 만드는 방법 String stringByConstructor = new String("Hello, World!")
    • 문자열 리터럴을 지정하는 방법 String stringByLiteral = "Hello, World!"
  • 생성자를 이용할 경우

    • new 연산자에 의해 메모리가 할당되기에

      항상 새로운 인스턴스가 생성

    • 아래의 코드에서

      String stringByConstructor1 = new String("Hello, World!");
      String stringByConstructor2 = new String("Hello, World!");

      두 변수 stringByConstructor1, stringByConstructor2는 동일한 인자를 받지만

      String가 참조하는 주소는 서로 다르다. 같은 값("Hello, World!")을 저장한 메모리가 두 군데라는 것이다.

      따라서 stringByConstructor1 != stringByConstructor2 이다!

  • 리터럴을 이용할 경우

    • 이미 존재하는 값을 재사용하는 것

    • 문자열 리터럴 값은 클래스가 메모리에 로드될 때 자동적으로 미리 생성된다!

    • 아래의 코드에서

      String stringByLiteral1 = "Hello, World!";
      String stringByLiteral2 = "Hello, World!";

      두 변수 stringByLiteral1, stringByLiteral2은 동일한 주소를 참조한다.

      생성자로 String 변수를 생성하는 것과 달리 이 경우 메모리가 낭비되지 않으며,

      stringByConstructor1 == stringByConstructor2 이다!

  • 따라서 문자열을 비교할 때는 ==연산자를 사용하지 말고 equals()메서드를 사용하자.

    • == 연산자의 경우 두 값이 동일한 인스턴스인가를 비교한다. (동등성, identity)

    • 반면 equals()는 동치성(equity)에 대한 비교를 목표하는, 모든 객체에 적용되는(Object) 메서드이다.

      String은 인코딩 방식이 같으며, 문자열 내용의 값이 동일한 경우 true를 리턴하는 식으로 equals()를 오버라이드 했다.

문자열 리터럴

  • 모든 문자열 리터럴 값은 컴파일 시에 클래스 파일에 저장된다.

    • 동일 내용의 문자열 리터럴은 한 번만 저장된다.

      문자열 리터럴도 String의 인스턴스이고, 불변이기에 같은 값이면 - 하나의 인스턴스를 공유하면 되기 때문이다.

    • 소스파일에 포함된 모든 리터럴의 목록을 담은 클래스 파일이 있다.

      이 파일이 클래스 로더에 의해 메모리에 올라갈 때, 리터럴들은 JVM 내의 상수 저장소(Constant pool)에 저장된다.

Constant Pool
  • 자바가 String 클래스를 특수하게 관리하는 수단

            String s = "";
            for (int i = 0; i < 10; i++) {
                s += i;
            }
            System.out.println("s = " + s);
    • 위의 코드가 실행될 경우

      Contstant Pool에는 "", "0", "01", "012", ...이 모두 저장된다.

  • 따라서 String에는 += 연산을 사용하는 것이 성능상 좋지 않다.

    • StringBuffer를 사용하라.

              StringBuffer sb = new StringBuffer();
              for (int i = 0; i < 10; i++) {
                  sb.append(i);
              }
              System.out.println("sb = " + sb);
      • 이 경우, "0", "01", "012"가 별개로 저장되는 것이 아니라 변경되는 식이다.
      • 메모리를 절약할 수 있다.

빈 문자열(empty string)

  • 길이가 0인 배열이 존재할 수 있듯이,

    길이가 0인 char[]value로 가지고 있는 String이 있을 수 있다 -> 빈 문자열

  • String emptyString = ""은 가능하지만,

    char emptyChar = ''은 불가능하다.

    • char 자료형 변수에는 반드시 하나의 문자를 지정해야 한다.
  • 초기화

    String s = null;
    char c = '\u0000';

    이런 방식의 초기화도 가능하지만,

    String s = "";
    char c = ' ';

    이런 방식의 초기화가 권장된다.

String관련 유용한 정보

  • String[] split(String regex): 인자로 받은 regex로 구분하여 문자열을 자른다.

  • 자바 8에서는 다음 두 기능이 추가되었다:

join()
  • static String join(CharSequence delimiter, CharSequence... elements)

  • static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

  • split()과 반대로 구분자로 문자열을 결합한다.

StringJoiner
  • StringJoiner() 생성 인자로 구분자를 받는다.
  • add(String s):로 합칠 String을 받는다.
유니코드의 보충문자
  • 유니코드는 2byte: 즉 16bit 문자체계다.
  • 하지만, 공간 부족으로 인해 20bit로 확장하였다: 보충 문자(supplementary characters), (JDK 1.5부터 지원)
    • 하나의 문자를 byte 크기 자료형인 char가 아니라 int로 다뤄야 하는 경우가 생겼다.
문자 인코딩 변환
  • getBytes(String charsetName)을 이용하여 인코딩 변환한 byte[]를 리턴받을 수 있다.
    • 매개변수는 String 말고 Charset자료형으로도 받을 수 있다(오버라이딩).
String.format()

printf()와 사용법이 동일하다.

기본형 ↔ String 변환
  • 기본형 → String: valueOf()를 이용하는 방식

    • 다른 자료형에 + ""해주는 방식보다 성능적으로 좋다.
    • Wrapper클래스로 값이 반환되지만, 오토박싱에 의해서 기본 자료형으로 자동 변환된다.
  • String → 다른 자료형(기본형도 포함): toString()

    • toString() 메서드는 Object의 메서드, 따라서 모든 객체에 존재한다.

      새 클래스를 만들 경우 적절히 오버라이드 하라.

StringBufferStringBuilder

  • String 클래스는 Constant Pool에 의해 관리되는 특이한 클래스로, 불변이기에

    +연산이 메모리 낭비를 일으킬 수 있다.

    StringBuffer를 사용하면 해결 가능

StringBuffer
  • String과 유사한 구조

    • char[] value에 값을 저장하는구조
  • 버퍼(buffer)

    • 문자열을 저장하고 편집하기 위한 공간

      value를 버퍼로 사용한다.

  • Thread-safe하다!

생성
  • StringBuffer 인스턴스가 생성될 때, 인자로 버퍼의 크기를 지정 가능하다.

    • 미지정시 16으로 초기화된다.

    • 버퍼의 길이가 부족해질 경우 버퍼의 크기를 늘려주는 작업이 이루어진다.

      배열의 복사는 메모리를 잡아먹기 때문에 적절한 양을 할당해주는 것이 필요하다.

변경
  • append(): 추가 기능, 현재 주소를 반환한다.

    • append(StringBuilder sb)가 규정되어 있기 때문에

      sb.append("a").append("b")형태의 연쇄 호출이 가능하다.`

StringBuffer vs StringBuilder
StringBufferStringBuilder
Thread-safe(동기화)동기화 기능을 뺐음
성능 면에서 손해 있음성능 면에서 더 나음
  • StringBuffer에서 동기화 기능만 뺀 클래스가 StringBuilder
  • 성능 차이가 매우 크진 않기에 왠만해선 StringBuffer 쓰자.

Object

  • 모든 객체의 최상위 객체

  • 즉, 모든 객체에는 Object의 메서드를 호출할 수 있음

  • 이 글에서는 간단하게 다루고 추후 이펙티브 자바 요약 정리 링크와 별도의 학습 포스트로 연결할 예정

Git

  • 개발자의 기본
  • 굳이 명령어로만 익힐 필요는 없다.
    • 명령어를 모르고 Tool 사용해도 된다.
    • 사용방법에 대해서는 알아야 한다.
      • branch 따기, merge 하기, conflict 해결 등

.gitignore

  • 포함해선 안 될 파일들

    • 빌드 결과
      • *.class, *.jar, build/ 단 라이브러리에 dependency 걸린 것들은 남기거나, 다운 받을 수 있게 해야
    • 바이너리
    • 제너레이트 가능한 파일들(논쟁)
      • gradle, gradlew , gradle.bat등 -> gradle wrapper명령어로 생성 가능
    • 로컬 설정들
    • 키/보안 관련 파일들
  • 로컬 환경에 의존적인 절대경로

  • 간단하게 처리하는 방식: gitignore.io

  • gradle wrapper를 ingore하느냐에 대한 논쟁

    • 포함하지 않아야 한다

      • gradle이 설치된 환경이나, IDE를 사용하는 환경(내장 gradle 보유)에서는 바로 내려받을 수 있다.
      • gradle wrapper 관련 파일들이 업데이트될 때마다 무의미한 커밋을 날리게 된다.
        • jar가 큰 용량을 차지하게 된다.
    • 포함해야 한다

      • 빌드 서버 등의 환경에서 gradle 등 빌드 툴이 설치 + 환경변수 설정 되어있지 않은 경우를 대비하기 위해서
      • 의존성 회피라는 측면에서
    • 참고

      • gitignore.io에서 생성한 .gitignore파일에는 ignore가 적용되지 않게 되어 있다.
      • 스프링 프로젝트의 경우에도 gradle wrapper를 포함시킨다.
    • 개인적인 결론

      • 학습 환경에서는 gradle wrapper를 포함시키지 않는다.

      • 운영하고자 하는 프로젝트의 경우 포함시키는 것을 우선하되,

        당연히 팀 컨벤션에 따라간다.

강의 외 참고 자료

  • String 부분은 남궁성, <자바의 정석>의 요약 + a임

0개의 댓글