코딩 테스트에서 시간 초과를 자주 마주치게 됩니다.

최적화를 위해 입출력 방식부터 최적화가 가능하지 점검해보는 것이 좋은데 일반적으로 많이 사용하는 Scanner와 System.out.print 대신 BufferedReader와 BufferedWriter를 활용하면 처리 속도를 크게 향상할 수 있습니다.

(물론, 이전에 풀이 로직의 시간복잡도를 먼저 확인하고 최적화 하는것이 중요하겠습니다.)

 

입출력 데이터의 양이 많지 않다면 두 방법이 큰 성능 차이를 보이지 않지만, 입출력 데이터의 양이 많아질 수록 성능차이가 발생할 수 있다고 합니다.

 

아래는 1,000,000개의 정수를 입력받고 출력하는 데 걸리는 시간을 비교한 표입니다.

방식 입력 속도(초) 출력 속도(초) 총 소요 시간(초)
Scanner/System.out.print 1.8 1.2 3
BufferedReader/BufferedWriter 0.3 0.3 0.6

 

 

성능차이가 발생하는 이유

Scanner는 입력할 때마다 필요한 자료형으로 변환하는 과정을 거치므로 처리 속도가 느려질 수 있습니다.

이후 사용하는 System.out.print는 출력이 발생할 때마다 버퍼를 비우는 작업이 이뤄지므로 성능이 저하될 수 있습니다.

 

반면 BufferedReader는 입력을 버퍼에 저장한 후 데이터를 한번에 읽어 오는 방식으로 I/O 작업 횟수를 줄여 성능을 향상합니다.

BufferedWriter도 마찬가지로 출력할 데이터를 버퍼에 저장한 후 한 번에 출력하는 방식으로 성능을 개선합니다.

write()함수로 데이터를 버퍼에 추가하고, flush()함수로 버퍼의 내용을 한꺼번에 출력함으로써 효율을 높입니다.

 

public class Main(){
	public static void main(String[] args) throws IOException{
    	Scanner sc = new Scanner(SYstem.in);
        int a = sc.nextInt();
        Systemout.println(a);
        
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int b = Integer.parseInt(br.readLine());
        bw.write(String.valueOf(b));	// 정수를 String형으로 변환하여 출력
        bw.flush();
    }
}

 

테스트코드를 작성하고 인풋데이터를 넣을 때, 예를들어 코딩테스트를 위해 작성한 코드에 예제 입력값을 넣어야 할 때, 매번 프로그램을 실행하고 예제 입력줄을 한 줄씩 넣는 방법을 사용하는데, 이 예제 입력창을 인텔리제이 환경에 띄우고 해당 입력창에 예제 입력줄을 전체 복사 붙여넣기해 즉시 사용하는 방법에 대해 알아봅니다.


1. 임의의 input.txt 파일 생성하기

예제입력을 작성할 빈 텍스트파일을 프로젝트 아무곳에 생성합니다.

 

2. 입력 리디렉션 설정하기

실행환경설정에서 편집을 클릭해 환경설정 창을 엽니다.

 

Modify optons를 선택하고, Redirect input을 체크해 'Redirect input from:' 옵션을 활성화합니다.

 

활성화 된 'Redirect input from:' 옵션에 1단계에서 만든 텍스트파일 경로를 입력하고 OK를 눌러 적용합니다.

 

3. 테스트 해보기

다음과 같이 'Hello World'를 입력텍스트 파일에 붙여넣고, 실행해보면 아래와같이 잘 출력되는것을 확인할 수 있습니다.

 

 

이후 여러줄의 예제입력이 추가로 필요한 경우에는 자신의 코드를 예제입력에 알맞게 작성해 분리해 사용하면 되겠습니다.

'Java > Basic' 카테고리의 다른 글

Scanner VS Buffered 의 차이  (1) 2025.08.07
Jar 파일과 War 파일 알아보기  (1) 2025.01.20
Garbage Collection 알아보기(작성 중)  (3) 2025.01.08
JVM(Java Virtual Machine)  (3) 2025.01.06

단순 공부를 하고 프로젝트를 진행할 때는 Tomcat이 내장되어있는 Jar파일 배포가 실행면에서 편리합니다.

그러나, 회사 업무로 프로젝트를 진행하며 인프라 쪽에서 Tomcat을 별도 관리하고 내부에 암호화 모듈을 설치 등 Tomcat에 별도의 작업을 진행하는 경우가 생기면서 기존 프로젝트의 빌드 및 배포를 Tomcat이 내장되어있지 않은 War 방식으로 바꿔야 했습니다.

 

Jar 파일과 War파일의 차이점을 정리해 봅니다.

 

 

1. Jar? War?

2. 기존의 Jar 프로젝트를 War파일 빌드 형식으로 바꾸기

3. .war 파일 생성 및 테스트

4. 추가


1. Jar? War?

1) .Jar(Java Archive)

jar는 Java 어플리케이션용 아카이브 파일입니다. 보통 배치 프로그램이나 CLI기반 Java 어플리케이션에서 사용됩니다.

Java 클래스 파일(.class), 관련 리소스(프로퍼티 파일, 설정 파일 등), 의존성 라이브러리를 포함합니다.

(실행 가능한 jar 파일의 경우 MANIFEST.MF) 파일에 메인 클래스 경로가 지정됩니다.

 

구성 디렉토리 구조는 아래와 같습니다.

testApp.jar
│
├── com/example/Main.class (메인 클래스)
├── resources/
│	└── application.properties
└── META-INF/
	└── MANIFEXT.MF (메인 클래스 지정)

그리고 이렇게 생성된 jar파일은 java -jar 명령어로 실행됩니다.

Spring Boot 기반 어플리케이션은 보통 jar 파일로 배포되며, 내장 WAS(Tomcat, Jetty 등)을 포함해 웹 어플리케이션을 실행할 수 있습니다.

 

2) .War(Web Application Archive)

war는 웹 어플리케이션용 아카이브 파일입니다. 주로 서블릿 컨테이너나 WAS에 배포하기 위해 사용됩니다.

JSP파일, HTML, CSS, JavaScript, 이미지 리소스, 서블릿 클래스 파일 등을 포함하며, 표준 디렉토리 구조(WEB-INF, META-INF 디렉토리)를 따릅니다.

testApp.war
│
├── intex.html (메인 클래스)
├── css/
├── js/
├── WEB-INF/
│	├── web.xml (배포 서술자)
│	└── classes/ (컴파일된 서블릿 클래스 파일)
│	└── lib/ (프로젝트에 필요한 JAR 파일)

Tomcat, JBoss, WebLogic 등 WAS 환경에서 실행되며, 웹 브라우저를 통해 사용자가 어플리케이션에 접근합니다.

구분 .war .jar
용도 웹 어플리케이션 배포용 독립 실행형 Java 프로그램 배포용
구성 JSP/HTML/CSS/서블릿 등 포함 Java 클래스, 리소스 파일 포함
실행 방식 WAS(Tomcat, JBOSS 등)에서 실행 java -jar로 실행 가능
주 사용 기술 서블릿/JSP 기반 Spring Boot, CLI, 배치 프로그램

2. 기존의 Jar 프로젝트를 War 파일 빌드 형식으로 바꾸기

1) SpringBootServletInitializer 추가

: War 배포 시 Spring Boot 어플리케이션이 외부 WAS에서 실행되도록 초기화 설정이 필요합니다.

(기존에 main 메서드로 어플리케이션 로직 시작을 실행했던 것 X, 초기화 설정을 추가해 어떤 클래스파일이 어플리케이션 소스인지 명시해 줍니다.)

public class ServletInitializer extends SpringBootsServletInitializer{
	@Override
    protected SpringApplicationBuilder configuer(SpringApplicationBuilder application){
    	return application.sources(MyApplication.class);
    }
}

 

2) 내장 WAS 비활성화

: 내장된 Tomcat은 .war 배포 시 필요하지 않으므로, 이를 provided로 설정합니다.

pom.xml 파일의 해당 설정을 바꿔줍니다.

 

3) 필요에 따라 web.xml 설정을 작성합니다.

: 외부 WAS에서 web.xml 파일을 필요로 하는 경우 작성합니다.

보통 Spring Boot 기반의 WAR 배포에서는 필요하지 않으나, 외부 WAS(Tomcat, JBoss, WebSphere 등)에서 특정 기능을 사용해야 하는 경우 web.xml이 필요할 수 있습니다.

- 서블릿 2.x 또는 3.0 이하 환경 (구형 WAS)

- 보안 필터 또는 인증 설정이 필요한 경우(외부 WAS에서 인증, 세션 관리 등을 설정하려는 경우)

- 외부 WAS에서 특정 리스터 또는 필터를 강제해야 할 경우(예: CORS, 인코딩 필터 등)

- 세션 타임아웃 설정이 필요한 경우(WAS 설정 파일에서 지정할 수 있지만, 어플리케이션 단위에서 설정하려는 경우)

- DispatcherServlet을 수동을 등록해야 하는 경우(Spring Boot가 아니라 Spring MVC 기반의 웹 어플리케이션에서)

 

이 외에 대부분의 Spring Boot + 서블릿 3.0 이상에서는 Web.xml을 필요로 하지 않습니다.


3. .war 파일 생성 및 테스트

: 메이븐 빌드도구를 사용한다면 해당 프로젝트 폴더에서 mvn clean package -Dskiptests(선택)을 통해 빌드를 실행합니다.

빌드가 완료되면 프로젝트 폴더의 target/디렉토리 안에 .war 파일이 생성됩니다.

이 .war 파일을 사용할 Tomcat의 webapps 폴더에 옮겨넣고, Tomcat을 재시작하면 됩니다.

 

[내가 사용하는 방법]

1. Tomcat경로/bin 폴더에서 ./shutdown.sh를 입력해 톰캣을 완전히 종료합니다.

2. Tomcat경로/logs 폴더의 로그 파일을 모두 삭제합니다.

3. Tomcat경로/webapps에 .war파일과 압축이 풀린 해당 파일명의 폴더까지 삭제합니다.

4. 새 .war 파일을 webapps에 옮기고 Tomcat경로/bin폴더에서 ./startup.sh를 실행합니다.

 

이후 정상적으로 실행 되었는지 디버깅이 필요하면 비워둔 logs폴더에 새로 생성된 로그 파일들을 확인합니다.

빌드 파일명을 'ROOT.war'로 만들기

pom.xml 파일의 build설정 항목에 finalName을 지정할 수 있습니다.

이곳에 이름을 ROOT로 지정하면, war파일을 빌드했을때 빌드파일의 이름이 ROOT.war로 빌드가 됩니다.

(기본적으로는 artifactId-version.war 형식으로 빌드됩니다.)

 

ROOT.war를 사용하는 이유

일반적으로 Tomcat에서 .war 파일을 배포할 때, ROOT.war로 설정하면 기본 컨텍스트(/ 경로)로 배포가 됩니다.

이게 무슨 말이냐 하면, 기본적으로 설정되는 artifactId-version.war 형식으로 배포를 하면 기본 경로가 http://example.com/artifactId-version/으로 설정됩니다.

이것을 ROOT.war 이름으로 배포해 webapps 폴더에 넣으면

http://exaple.com/ 경로로 기본 경로를 사용할 수 있습니다.

 

물론 .war 파일 이름을 ROOT.war로 하지 않고도 기본 컨텍스트를 지정할 수 있습니다.

1. conf/server.xml 설정 변경하기

    - Tomcat경로/conf 폴더에 server.xml 폴더를 열어 컨텍스트 경로를 직접 지정할 수도 있습니다.

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
    <Context path="/" docBase="myapp" />
</Host>

    이렇게 하면 myapp.war 파일을 사용하면서도 컨텍스트 경로는 /(루트)로 설정할 수 있습니다.

2. webapps/ROOT/ 폴더에 직접 배포하기

    - Tomcat경로/webapps폴더 안에 ROOT 디렉토리를 만들고, 빌드한 .war파일을 안에 압축을 해제합니다.


4. 추가

Root.war 파일과 ROOT.war를 조심하시오.

Tomcat은 기본 컨텍스트(/ 경로)에 배포할 .war파일의 이름을 ROOT.war로 인식하기 때문에, 서버에 scp 명령어를 사용해 배포파일을 올리다가 Root.war로 올려버리면 Tomcat은 이를 올바르게 배포하지 못하고 무시하거나 동작이 잘못될 수 있습니다. 🥲🥲

Garbage Collection

: 줄여서 GC 라고 부르기도 한다. 가비지 컬렉션은 메모리 관리 기법중 하나로, 동적으로 할당된 메모리 영역 중 더 이상 쓰이지 않는 영역을 자동으로 찾아내어 해제하는 기능이다.

옛날 언어들은 동적 메모리 할당 기능이 없거나, C처럼 프로그래머가 할당한 뒤 수동으로 해제까지 해 줘야 하는 방식이었는데, 사람이 하는 일이 항상 완벽할 수 없기 때문에 메모리 누수가 생기거나, 해제했던 메모리를 실수로 다시 사용하거나 해제헀던 메모리를 다시 해제하는 실수가 일어나 온갖 버그가 양산되었다. 이를 해결하기 위해 고안된 방법이 가비지 컬렉션이다.

 

가비지 컬렉션에 대해 알아보기 전에 메모리 구조 알아보기 →

 

 

 

https://namu.wiki/w/Java%20Virtual%20Machine

Java Virtual Machine(자바 가상 머신)으로 나무위키에는 Java 컴파일러가 프론트엔드를 담당한다면 Java 가상머신은 코드 최적화와 백엔드를 담당한다고 쓰여있다.

 

그렇다면 컴파일러는 무엇일까 ?

Compiler 알아보기 →


작성한 Java 소스코드는 javac 컴파일러를 거쳐 바이트코드로 변환되고, 이 바이트 코드는 JRE(Java Runtime Environment)에 들어있는 java classloader에 의해 JVM으로 적재되고 JVM에 적재된 바이트코드를 JIT(Just In Time)컴파일 방식으로 실행하는 컴퓨터의 OS 및 CPU 아키텍처용 기계어로 번역되어 수행된다.

 

JVM의 강점은 '플랫폼 독립'적으로 JVM이 실행가능한 환경이라면 어디서든 Java 프로그램이 실행될 수 있도록 하는 것이다.

"Write Once, Run Anywhere"

 

단, 특정 운영체제의 특수한 기능을 호출하거나 하드웨어를 제어하는 등의 일은 JVM으로 할 수 없으며, JNI 같은 Navite 코드를 호출하기 위한 인터페이스를 거쳐야 한다. (이 부분에 대해 찾아볼 것 !)

 

또 Java 가상머신이라고 Java 바이트 코드만 인식하는 것이 아니라, Kotlin, Scala, Groovy처럼 Java에서 파생된 언어들의 바이트 코드 또한 인식할 수 있다.

 

다만, 이 바이트 코드가 실제 기계에서 실행되는 것이 아니라, JVM의 해석단계를 거치므로 같은 기능의 네이티브 언어(C, C++, Rust, Go 등)보다 실행속도가 느리다고 한다.

(현재는 JIT 컴파일의 도입과 하드웨어 발전으로 성능이 개선되었다고 한다 !)

 

가비지 콜렉션(GC: Garbage Collection) 또한 Java 계열의 강력한 무기라고 할 수 있을까?

JVM은 가비지 컬렉션을 수행하여 할당되었다가 더 이상 쓰이지 않는 메모리를 자동으로 회수한다.

Garbage Collection 알아보기 →(미완)


Java Class 파일 단독으로 실행시켜보기

국비학원에서 수업을 들을 때, JRE, JDK를 설치하고나서 강사님께서 가장 먼저 메모장에 클래스파일을 간단하게 작성해서 javac명령어를 사용해 클래스 파일 실행을 보여주신 적이 있다. 그땐 몰랐지만 지금은 알 수 있다 😁

public class test {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

test.txt 메모장 파일을 생성해서 위와 같이 코드를 작성한다, 이후 저장하고 확장자명을 .java로 변경한다.

 

cmd 또는 powershell 명령 프롬프트를 열어, 메모장이 있는 폴더로 이동해

javac test.java 명령어를 입력한다.

그러면 같은 폴더에 test.class 파일이 생성된다.

 

다시 명령 프롬프트에 java test 명령어를 입력하면, 프롬프트에 Hello World가 출력되며 Class 파일이 실행된다.

 

이것으로 Java 소스파일의 컴파일 후 실행 과정을 간단하게 진행해 보았다.

+ Recent posts