자바 클래스 파일을 jar 로 묶고 사용하기

Java|2021. 2. 26. 23:22

자바로 API 를 만들어서 외부에 라이브러리로 제공할 때 클래스 파일로 제공한다면 클래스 파일 갯수가 많을 경우 라이브러리 사용자 입장에서는 사용에 부담을 느낄 수 있다.

이런 경우 라이브러리에 포함되는 모든 클래스 파일을 하나의 아카이브 (jar) 로 묶어서 제공한다면 효율적으로 사용할 수 있다.

jar 파일의 경우 압축해제 없이 jar 파일 내에 있는 클래스에 접근이 가능하기 때문에 유용하다.

 

우선 테스트를 위해 두 개의 클래스 파일을 생성해보자.

 

테스트를 위한 클래스 파일

 

클래스 내용은 중요하지 않다.

아무 클래스 파일이라도 상관없다.

이제 이 두 클래스 파일을 하나의 jar 파일로 묶을 차례다.

 

커맨드 입력 라인에서 다음과 같이 입력한다.

 

C:\> jar cvf library.jar ./library/*.class
added manifest
adding: library/A.class(in = 176) (out= 150)(deflated 14%)
adding: library/B.class(in = 176) (out= 150)(deflated 14%)

 

나는 C 드라이브에 library 디렉터리를 만들고 이 디렉터리에 클래스 파일들을 위치시켰기 때문에 ./library/*.class 라고 입력했다.

library.jar 는 생성할 jar 파일의 이름인데, 확장자만 .jar 로 적어준다면 어떤 이름이든 상관없다.

added manifest 메세지가 나온다면 정상적으로 jar 파일이 생성된것이다.

 

생성된 jar 파일

 

이제 이 jar 파일을 배포하기만 하면 된다.

 

만약, 라이브러리 사용자 입장에서 이 jar 파일을 사용하고 싶다면 클래스 패스에 jar파일이 존재하는 디렉터리를 추가하고 사용하면 된다.

아주 간단하다.

'Java' 카테고리의 다른 글

JShell 을 이용해 자바 테스트하기  (0) 2021.02.26

댓글()

JShell 을 이용해 자바 테스트하기

Java|2021. 2. 26. 22:53

Java 9 버전부터 기본 제공 툴에 JShell 을 포함시켰다.

JShell 은 자바 코드를 미리 검증해보는 프로토타이핑을 위한 도구이기 때문에 처음 학습하면서 예제를 간단히 실습해보거나 다른 라이브러리를 실험해볼 때 유용하다.

GUI 가 존재하는 툴은 아니기 때문에 커맨드 라인(윈도우면 CMD 창)에서 실행해야한다.

 

JShell 의 쓰임새

JShell 은 한줄 씩 읽고(Read) 평가 후 (Evalution) 결과를 출력(Print) 하고 계속해서 다음 코드 입력을 대기(Loop)하기 때문에 REPL 이라고도 한다,

즉, 인터프리터 처럼 동작하기 때문에 익숙하지 않은 라이브러리를 실험하거나 간단한 코드의 동작을 파악할 때 유용하게 사용할 수 있다.

하지만 오라클 공식 문서에서도 언급하듯이 JShell 이 이클립스와 같은 IDE 를 완전히 대체할 수 있는 도구는 아니다.

오라클 공식 문서에서는 JShell 에서 코드의 동작 여부를 확인하고 IDE 에 붙여넣어서 프로그래밍하는것을 권유한다.

 

 

JShell 실행

JShell 은 JDK 9 이상 버전 부터 제공되기 때문에 JShell 을 실행하기 위해선 먼저 JDK 9 이상 버전이 설치되어 있어야한다.

그리고, 환경변수 path 에 /jdk설치디렉터리/bin 경로가 등록되어 있다면, 커맨드 입력 창(CMD)을 열어 다음과 같이 JShell 을 실행할 수 있다.

 

% jshell
|  Welcome to JShell -- Version 15.0.2
|  For an introduction type: /help intro

jshell>

 

(파악하기 쉽게 % 가 있는 줄은 사용자가 직접 입력한 명령어라고 가정한다)

 

JShell 을 실행할때 verbose 옵션을 주어서 verbose 모드로 실행할 수 있는데, 간단히 말해서 JShell 이 명령을 실행하고 결과를 출력할 때 좀 더 자세한 도움말을 주는 모드다.

verbose 모드로 실행할 땐 다음과 같이 실행한다.

 

% jshell -v
|  Welcome to JShell -- Version 15.0.2
|  For an introduction type: /help intro

jshell>

 

다음은 일반 모드로 실행했을 때의 실행결과와 verbose 모드로 실행했을 때의 실행결과를 비교한 모습이다.

 

1. 일반 모드 실행 시 (변수 선언)

% jshell
|  Welcome to JShell -- Version 15.0.2
|  For an introduction type: /help intro

jshell> int val = 0;
val == > 0 // 변수 val 을 0으로 초기화 했다는 의미

 

2. verbose 모드 실행 시 (변수 선언)

% jshell -v
|  Welcome to JShell -- Version 15.0.2
|  For an introduction type: /help intro

jshell> int val = 0;
val ==> 0
|  created variable val : int

 

결과를 보면 일반 모드보다 verbose 모드가 더 친절하다는 걸 알 수 있다.

하지만, 명령의 갯수가 늘어나고 복잡한 코드가 입력될 경우 난잡해 보일 수 있으니 일반 모드를 사용하도록 하자.

 

JShell 종료

JShell 을 종료할 땐 다음과 같이 입력한다.

jshell> /exit
|  Goodbye

 

 

스니펫

위에서 JShell 을 이용해 간단히 변수를 선언하는 방법을 배웠다.

이렇게 JShell 가 처리하는 하나의 명령을 스니펫이라고 한다.

기본적으로 자바는 문장의 끝에 세미콜론을 붙여줘야하지만 스니펫은 안붙여도 된다는 장점이 있다.

 

 

변수

JShell 에서 변수를 선언하고 사용할 수도 있지만 변수를 선언하지 않고 표현식만 입력하고 변수로 활용할 수 있다.

이때는 JShell 이 자동으로 생성하는 변수에 초기화되는데, 이때 JShell 이 자동으로 생성하는 변수를 가리켜 스크래치 변수라고 한다.

 

jshell> 1 + 2
$1 ==> 3   // 스크래치 변수

 

이 스크래치 변수는 이후 다른 스니펫에서 사용 가능하다.

 

jshell> Math.multiplyExact($1,$1)
$2 ==> 9

 

변수를 직접 선언해서 사용할 경우, 동일한 변수 선언 스니펫을 여러번 입력할 수 있는데 이때는 기존 변수의 값에 덮어쓰게 된다.

 

jshell> int val = 0
val ==> 0

jshell> int val = 2
val ==> 2

 

또한 변수의 타입도 변경이 가능하다.

 

jshell> int val = 0
val ==> 0

jshell> int val = 2
val ==> 2

jshell> String val
val ==> null

 

메소드

JShell 로 메소드 선언 및 호출 또한 가능하다.

 

jshell> int getRandomInt(){
   ...>     Random random = new Random();
   ...>     return random.nextInt();
   ...> }
|  created method getRandomInt()

jshell> getRandomInt();
$2 ==> -699245597

 

변수와 마찬가지로 메소드 또한 중복해서 정의할 경우 기존 내용에 덮어씌여진다.

또한, 아직 정의되지 않은 메소드를 사용하는 코드를 작성할수도 있다.

단, 이 경우 해당 코드를 실행하기 위해선 아직 정의되지 않았던 메소드를 정의해야한다.

 

jshell> int getRandomUnsigendInt(){
   ...>     Random random = new Random();
   ...>     return toUnsigendInt(random.nextInt());
   ...> }
|  created method getRandomUnsigendInt(), however, it cannot be invoked until method toUnsigendInt(int) is declared

// 아직 정의되지 않은 메소드를 정의하지 않았을 경우
jshell> getRandomUnsignedInt()
|  Error:
|  cannot find symbol
|    symbol:   method getRandomUnsignedInt()
|  getRandomUnsignedInt()
|  ^------------------^

// 아직 정의되지 않은 메소드를 정의
jshell> int toUnsigendInt(int value){
   ...>     return Math.abs(value);
   ...> }
|  created method toUnsigendInt(int)

jshell> getRandomUnsigendInt()
$5 ==> 433089761

 

이렇게 사전에 정의되지 않은 메소드를 사용하는 방식을 가리켜 "사전 참조" 라고 부른다.

 

 

편집 모드

JShell 에서는 메소드 뿐만 아니라 클래스, 인터페이스 등 자바에서 제공하는 모든 문법을 사용할 수 있다.

하지만, 이렇게 커맨드 입력 라인으로 코드를 작성하기에는 가독성 문제도 그렇고 추후 잘못된 내용을 편집하기 까다롭다는 단점이 있다.

이러한 단점을 해결하기 위해 외부 편집기를 제공한다.

외부 편집기를 사용하면 메모장 처럼 코드를 한눈에 파악할 수 있고 편집에도 용이하다.

또한 외부 편집기에서 작성한 스니펫을 실시간으로 커맨드 라인에 적용할 수도 있다.

외부 편집기를 실행하는 방법은 다음과 같다.

 

jshell> /edit

외부 편집기 실행 모습

 

여기서 코드를 수정 및 추가하고 Accept 버튼을 누르면 커맨드 라인에도 동시에 입력되고 실행되는 것을 볼 수 있다.

Exit 버튼을 누르면 외부 편집기를 종료하고 커맨드 입력 라인 모드로 돌아간다.

 

 

유용한 단축키

단축키 설명
Tab 자동완성 기능
- 클래스 및 메소드 명 자동완성
- 명령어에 사용할 경우 탭을 누를 때 마다 다른 설명출력
Shift + Tab -> V 값에 사용할 경우 값을 평가해 해당 값을 저장할 수 있는 변수 선언문으로 자동변환
Shift + Tab -> i 사용하려는 클래스가 포함된 패키지 목록 출력
- 번호 선택 후 엔터를 누르면 import 문이 자동으로 추가
Ctrl + R 검색 모드 실행

 

 

유용한 명령어

명령어 설명
/var 현재까지 선언된 변수 리스트 출력
/methods 현재까지 정의된 메소드 리스트 출력
/list 현재까지 입력된 스니펫 리스트 출력

 

 

지금까지 JShell 에 대해 간단히 알아봤는데, 사실 이 외에도 아주 다양한 기능을 제공하고 있다.

자세한 내용은 이 글을 작성하는데에 참고했던 오라클 공식 문서에서 살펴보면 될 것 같다.

 

오라클 공식 문서: docs.oracle.com/javase/9/jshell/toc.htm

'Java' 카테고리의 다른 글

자바 클래스 파일을 jar 로 묶고 사용하기  (0) 2021.02.26

댓글()