14P by GN⁺ 14시간전 | ★ favorite | 댓글 4개
  • 이제 Java의 첫 번째 프로그램은 더 이상 public static void main(String[] args) 로 시작하지 않고, 단순화된 void main() 문법으로 작성 가능해짐
  • 새로운 문법에서는 IO.readlnIO.println 같은 간단한 호출만으로 입출력을 처리할 수 있어 코드가 훨씬 직관적으로 바뀜
  • 기존의 new Scanner(System.in), System.out.println 같은 장황한 구문은 불필요해짐
  • 그동안의 불편함이 “마침내 끝남”, 이제 Java의 기본 구조가 가벼워지면서 입문 장벽이 낮아지고 학습 친화성이 크게 향상될 것

  • 전통적으로 Java는 프로그램 시작을 위해 public static void main(String[] args) 라는 긴 선언을 요구했음
  • 그러나 2025년 9월 16일 기준, Java의 가장 첫 번째 예제로 여겨지던 main 함수의 복잡한 선언문이 새로운 간단한 형태로 대체됨
  • 기존 방식:
    public class Main {  
        public static void main(String[] args) {  
            Scanner scanner = new Scanner(System.in);  
            System.out.print("What is your name? ");  
            String name = scanner.nextLine();  
            System.out.println("Hello, " + name);  
        }  
    }  
    
  • 새로운 방식:
    void main() {  
        var name = IO.readln("What is your name? ");  
        IO.println("Hello, " + name);  
    }  
    
  • 초보자에게는 불필요하게 장황하고, “주술적 주문”처럼 외워야만 했던 구문이라는 비판을 받아왔음
  • 기존 선언문의 번거로움난해함을 해소하고, 간결한 문법 도입으로 코드 가독성이 높아졌으며, Java 입문의 진입 장벽이 크게 낮아짐
    • 더 이상 Scanner, System.out.println 등 복잡한 객체 생성과 호출을 기본 예제로 쓰지 않음

Good Fucking Riddance = “드디어 없어져서 속 시원하다. 잘 가라”

자바를 다시 배워야 하나..

김한수는 살아 있다

The main is dead. Long live the main!

Hacker News 의견
  • 시간이 지나면서 이런 생소한 코드들이 점점 이해가 되어가는 과정이 그리워질 것 같음. 처음에 Python을 배우고 나서 Java로 넘어갔을 때 'void'나 'String[]' 같은 타입이 무엇을 의미하는지 몰라서 신기했음. 타입을 배우고 나니 이해가 되었고, 그 다음엔 class와 object 개념, 그리고 main이 왜 static 메서드로 존재하는지 알게 되었음. 더 깊이 들어가면서 이 클래스가 언제 호출되는지도 배우면서 처음엔 단순한 보일러플레이트 같던 코드가 점점 말이 되기 시작했음. 아마 경력이 많은 Java 개발자는 저보다 더 많은 의미를 한 줄에 읽어낼 수 있을 것 같음. 그래도 이제는 없어져서 속 시원함

    • 정말 속 시원함. 지난 30년간 소프트웨어 교육은 개발자에게 '공학'이라는 이름으로 쓸데없는 복잡성을 생산하도록 가르쳐왔음. 예를 들어, A 개발자는 엔트리 포인트나 콜백, 인터페이스 등 무엇이든 필요에 따라 클래스를 만듦. 그 결과 우리는 클래스를 가지게 됨. B 개발자는 클래스에 인스턴스 변수를 추가하며 전체를 변경 가능하게 만들고, 이로 인해 "구현의 진흙탕"이 형성됨. 이후 다른 개발자가 코드 재사용을 위해 상속을 추가하지만, 이로 인해 더 많은 복잡성과 동적 디스패치 악몽이 생김. 결국 참조 순환(rference cycle)이 생겨 객체들의 연결관계가 꼬이게 됨. 시간이 지날수록 리팩토링은 점점 힘들고 귀찮아져서, 결국 코드를 지우고 새로 시작하게 됨

    • 대학에서 처음 프로그래밍을 배울 때 이 코드를 보고 교수님이 "보통은 코드 설명을 다 해주겠지만, 이 부분은 그냥 일단 받아들이라"고 했던 기억이 있음. 나중에 돌아보니 내가 저 코드를 다 이해하고 있다는 걸 깨달았을 때 꽤 멋졌던 경험임. 그래도 이제 시대가 바뀌는 것 같아서 속이 후련함

    • 사실 static 클래스 메서드는 프로그램의 단일 진입점(entry point)이 반드시 클래스와 관련되어야 한다는 현실 부정에 가까움. C++ 뿐만 아니라 Python, Ruby처럼 절차지향의 현실을 인정한 언어도 있는데, Java는 마치 사용자의 눈을 가리고 "완벽한 OOP 세계"로 몰아넣는 듯함

    • 구식 class 기반 방식을 알던 입장에서 새로운 스타일(Java 21의 unnamed classes 등)이 더 질문을 던지는 것 같음. 정말 "모든 것이 객체"인 Java를 절차지향 언어로 바꾼 건지 의문임. 만약 커맨드라인 인자가 필요할 때는 어떻게 해야 하는지 궁금함. 나는 주로 Java를 피해서 잘 몰랐지만, 이건 진심 궁금해서 묻는 질문임

  • Java 1.2 시절에는 표준입력을 다음과 같이 읽었음. Scanner class는 처음이라 생소함

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String input = in.readLine();
  • 나도 비슷한 경험임. 오래전에 Java를 하다 보니 public static void main 패턴은 익숙했는데, Scanner 사용법이 어색해서 이유를 정확히 이해하지 못했었음

  • 내 경험상 대형 프로젝트에서 수십 년 동안 일해왔기 때문에, main 함수가 어떻게 써있는지는 내 일상이나 커리어에는 전혀 영향을 끼치지 않음. 여러분은 이런 변화가 실제로 얼마나 영향을 주는지 궁금함

    • Android 개발자라면 main이란 개념 자체가 없었음. 솔직히 trivial한 Hello World의 구현이 못생겼다고 해서 그 언어가 그 이상을 잘 처리하는지의 척도가 된다고 생각하지 않음

    • 많은 사람들이 Java로 프로그래밍 입문을 하면서 main을 수십 번 타이핑했지만, 그게 무슨 의미인지 전혀 모르고 있었음

    • 실무 개발자에게는 크게 영향이 없지만, 초보자에게는 중요한 문제임. 예전에 Java를 가르쳤는데, "Hello, World"를 찍기 전에 외워야 하는 마법 주문(보일러플레이트)이 학생들에겐 진입장벽으로 작동했음

    • 명령줄 인터페이스를 만든다면 영향이 있을 수 있겠지만, Java로 CLI를 만드는 경우 그리 많지 않음

    • 나는 최근 5년 정도 codebase에서 main을 본 적이 없음. 그리고 거의 새로운 클래스를 직접 만들기보다는 보통 프레임워크 특정 클래스를 구현하거나 확장하는 형태임

  • JEP 445: Unnamed Classes and Instance Main Methods가 Java 21에 릴리스됨
    https://openjdk.org/jeps/445

    • 아쉽게도 이 기능이 단일 파일 프로그램에서만 쓸 수 있도록 나온 점이 아쉬움. 패키지 레벨 메소드나 여러 클래스/레코드를 파일에 둘 수 있게 허용했다면 Java가 더 좋아졌을 것 같음. 하지만 어쨌든 "Java 코드를 일반적으로 작성하는 방식에 미치는 영향"은 원하지 않았던 것 같음
  • 30년만에 Java가 마침내 꽤 괜찮은 언어로 진화하는 모습이 놀라움

    • 나는 프레임워크 없이 순수하게 Java와 C++로 많은 코드를 짰었고, 이 때는 보일러플레이트가 훨씬 적고 간단했음. 진짜 편리함을 체감한 건 약 10년 전 lambda가 추가됐을 때임. 람다 도입 이후 코드의 분량이 줄어들고, 굉장히 쾌적해짐을 느꼈음. Java는 오래도록 엄청나게 명시적이고, 사소한 것에도 오타 체크만 해주는 것 같은 불필요한 반복문이 많았음. Kotlin이 뜨기 전까지 이런 분위기였는데, 이후 lambda와 익명클래스 등으로 개발 경험이 크게 나아졌음

    • Java가 끔찍했던 언어라는 주장은 너무 과장임

    • 반면 Python 같은 언어는 30년이 지났어도 아직도 불편하다고 생각함

    • 아마도 정말 나쁜 언어를 경험해 본 적이 없거나 "끔찍하지 않음"의 기준이 굉장히 높다고 추측함

    • 그래도 Java는 뛰어난 하위호환성과 패키지 관리 시스템이 있다는 점은 대단함

  • 이전 댓글에서 언급한 내용인데, Java 개발자로서 python은 오히려 이상하지만 지금 방식이 나쁘다고 생각하지 않음. 다만 추상화의 기본을 이해하지 못한 채 바로 프로그래밍을 하면 "프로그래밍 입문"에는 좋은 선택이 아닐 수 있다고 봄. 어떤 도구가 목적 지향, 패러다임 지향 등으로 설계되면 때로는 극단적 추상화가 일어날 수 있음. Java는 OOP에 초점을 두고 설계되어있기 때문에 인터페이스 같은 블록 단위 사고가 자연스러움. 메서드/클래스의 접근제한자 역시 누구를 위한 것인지에 따라 명확히 구분함(public, protected, default, private 등). 즉, Java로의 입문은 사용자(프로그래머)를 향한 interface의 노출로부터 시작함. 이상해 보일 순 있지만, 적어도 일관성은 있음

    • 무거운 문법은 OOP와 직접적인 상관이 없음. Java가 등장하기 전 OOP의 어떤 정의도 "함수는 클래스 밖에 존재할 수 없다"라고 말하지 않았음. Sun은 오랫동안 스탠드얼론 함수 개념을 거부했고(정적 import는 Java 5, 클로저는 Java 8, compact source 파일/instance main은 이제서야 도입), 그 결과 모든 함수가 여전히 클래스 내부에 있음(실용성과 호환성 때문이지, 철학적 이유는 아님). "모든 것이 객체"를 고집하려 했지만, 실제로는 primitive 값을 도입하는 모순도 있었음. 함수가 반드시 클래스 내부에 있어야 할 실용적 이득은 없음. 오히려 정수와 같은 값에 메서드를 정의할 수 있었으면 더 좋았을 것임. 참고로 Smalltalk 같은 "순수 OOP" 언어에서는 클래스 밖에 함수를 자유롭게 정의할 수 있고 REPL에서도 직접 코드를 실행할 수 있음
      관련 링크

    • Hello World가 중요한 이유는, 프로그램 실행을 위한 보일러플레이트와 실제 출력 코드를 동시에 보여줄 수 있기 때문임. 또한 빌드 도구 설정이라는 측면에서도, 일부는 '보일러플레이트'라기보다는 실습/도구 설정을 위한 절차임. 이를 바로 설명해주면 큰 문제는 아님

  • 만약 컴파일러 트릭으로 내부에서 클래스를 생성한다면 그저 보여주기식 변화에 불과함. 다른 top-level 함수가 허용되지 않는다면 결국 특이 케이스일 뿐이라 여전히 어색함

    • C#은 9.0부터 top level statement를 지원하지만, 결국 내부적으로는 정적 메서드로 변환됨. 여러 top level 함수도 비슷하게 동작함. 실제 예시: C# decompiled example
      이런 트릭은 실제로 유용한 컴파일러 변환의 예시임(closure, async state machine 등). 이번 변화도 그런 셈임

    • C/C++에서 main()에서만 기본 return 0이 적용되는 것도 비슷하게 어색하게 느껴짐

    • 만약 main만 top-level 함수로 허용되고, 다른 것은 불가능하다면 이 역시 별로 좋은 변화가 아니라고 봄

  • Java 코드 예제에서 import 라인을 왜 생략하는지 이해가 안됨. 보일러플레이트의 복잡함을 보여주려면 import도 반드시 써줘야 할 것 같음

    • 보통 IDE가 import를 자동 관리해주기 때문에 신경쓰지 않음. IO 관련 클래스라면 compact 예제에선 따로 import가 필요 없어서 실제로 코드가 저대로 동작함

    • 대부분의 Java IDE는 import를 자동으로 관리해줌

  • public static void main(String[] args)라는 엔트리포인트를 C#처럼 top-level statement 패러다임으로 추상화하면 보일러플레이트를 줄이고 코드가 간결해질 것 같은데, 왜 그렇게 안 했는지 궁금함

    • Paving the on-ramp 문서를 참고하길 바람

    • 엔트리 포인트가 특수한 예외 케이스로 존재한다면 이미 OOP의 한계를 인정하는 셈임. 그렇다면 과감하게 새로운 대안을 설계하는 편이 낫지 않을까 생각함

  • unnamed class 방식을 활용하면 전역 변수 구현이 쉬워지고, 핫리로드도 가능하면서 문법이 간결해진다는 점이 좋다고 생각함. 한편, Java 파일은 이름이 public class와 동일해야 한다는 제약이 있어서, 차라리 public class X { } 부분을 옵션으로 두고 필요한 경우만 쓰게 했어도 됐을 듯함. 왜 익명 클래스를 도입해야 했는지 잘 이해가 안 됨
    컴파일러는 여전히 HelloWorld.class 같은 클래스로 변환하므로, 그 이름은 구현 세부사항일 뿐 실제로 소스코드에선 직접적으로 쓸 순 없음
    https://openjdk.org/jeps/445