JDK & OpenJDK

System/Linux 2012. 4. 5. 13:13
























OpenJDK (Open Java Development Kit) is a free and open source implementation of the Java programming language.[2] It is the result of an effort Sun Microsystems began in 2006. The implementation is licensed under the GNU General Public License (GPL) with alinking exception, which exempts components of the Java class library from the GPLlicensing terms. OpenJDK is the official Java SE 7 reference implementation.[3][4]

Contents

  [hide

[edit]History

[edit]Sun's promise and initial release

Sun announced in JavaOne 2006 that Java would become open-source software,[5][6] and on October 25, 2006, at the Oracle OpenWorld conference,Jonathan Schwartz said that the company intended to announce the open-sourcing of the core Java Platform within 30 to 60 days.[7]

Sun released the Java HotSpot virtual machine and compiler as free software under the GNU General Public License on November 13, 2006, with a promise that the rest of the JDK (which includes the Java Runtime Environment) would be placed under the GPL by March 2007, "except for a few components that Sun does not have the right to publish in source form under the GPL".[8] According to free-software advocate Richard Stallman, this would end the "Java trap", the vendor lock-in that he argues applied to Java and programs written in Java.[9]

[edit]Release of the class library

Following their promise to release a Java Development Kit (JDK) based almost completely on free and open source code in the first half of 2007,[10] Sun released the complete source code of the Java Class Library under the GPL on May 8, 2007, except for some limited parts that some third parties licensed to Sun that rejected the terms of the GPL.[11] Included in the list of encumbered parts were several major components of the Java graphical user interface (GUI). Sun stated that it planned to replace the remaining proprietary components with alternative implementations and to make the class library completely free.[12]

[edit]Community improvements

On November 5, 2007, Red Hat announced an agreement with Sun, signing Sun's broad contributor agreement (which covers participation in all Sun-led free and open source software projects by all Red Hat engineers) and Sun's OpenJDK Community Technology Compatibility Kit (TCK) License Agreement (which gives the company access to the test suite that determines whether a project based on OpenJDK complies with the Java SE 6 specification).[13]

Also on November 2007, the Porters Group was created on OpenJDK[14] to aid in efforts to port OpenJDK to different processor architectures andoperating systems. The BSD porting projects,[15] led by Kurt Miller and Greg Lewis and the Mac OS X porting project (based on the BSD one)SoyLatte led by Landon Fuller[16] have expressed interest in joining OpenJDK via the Porters Group and as of January 2008 are part of the mailing list discussions. Another project pending formalization on the Porters Group is the Haiku Java Team, led by Bryan Varner.[17]

On December 2007, Sun moved the revision control of OpenJDK from TeamWare to Mercurial, as part of the process of releasing it to open sourcecommunities.[18][19]

OpenJDK has comparatively strict procedures of accepting code contributions: every proposed contribution must be reviewed by two of Sun's engineers and the contributor must have signed the Sun/Oracle Contributor Agreement.(SCA/OCA[20]) Preferably, there should also be a jtreg[21] test demonstrating that the bug has been fixed. Initially, the external patch submission process was slow[22] and commits to the codebase were only made by Sun engineers, until September 2008.[23] The process has improved and, as of 2010, simple patches and backports from OpenJDK 7 to OpenJDK 6 can take place within hours rather than days.[24]

[edit]Collaboration with IBM, Apple, and SAP

On October 11, 2010, IBM, by far the biggest participant in the Apache Harmony project, decided to join Oracle on the OpenJDK project, effectively shifting its efforts from Harmony to OpenJDK.[25][26] Bob Sutor, IBM's head of Linux and open source, blogged that "IBM will be shifting its development effort from the Apache Project Harmony to OpenJDK".[27]

On November 12, 2010, Apple Inc. (just three weeks after deprecating its own Java runtime port[28]) and Oracle Corporation announced the OpenJDK project for Mac OS X. Apple will contribute most of the key components, tools and technology required for a Java SE 7 implementation on Mac OS X, including a 32-bit and 64-bit HotSpot-based Java virtual machine, class libraries, a networking stack and the foundation for a new graphical client.[29]

On January 11, 2011, the Mac OS X Port Project was created on OpenJDK, and Apple made the first public contribution of code to the project. The initial Apple contribution built on the OpenJDK BSD port.[30]

In July 2011, SAP AG announced that SAP officially joined the OpenJDK project.[31]

[edit]Status

[edit]Supported JDK versions

OpenJDK was initially based only on the JDK 7 version of the Java platform.[32]

Since February 15, 2008, there are two separate OpenJDK projects:

  • The main OpenJDK project, which is based on JDK 7.
  • The OpenJDK 6 project, a cut-down version of OpenJDK 7,[33] which provides an open-source version of Java 6.[34]

[edit]Compiler and virtual machine

Sun's Java compiler, javac, and HotSpot (the virtual machine), are now under a GPL license.

[edit]Class library

As of the first May 2007 release, 4% of the OpenJDK class library remained proprietary.[35] By the appearance of OpenJDK 6 in May 2008, less than 1% (the SNMP implementation,[36] which is not part of the Java specification) remained,[37] making it possible to build OpenJDK without any binary plugs.[36]The binary plug requirement was later dropped from OpenJDK 7 as part of b53 in April 2009.[38]

This was made possible, over the course of the first year, by the work of Sun Microsystems and the OpenJDK community. Each encumbrance[39] was either released as free and open source software or replaced with an alternative. Beginning in December 2010, all the so called binary plugs were replaced by Open source replacements, making the whole JDK open sourced and the binary plugs not necessary anymore.[40]

Sun has made continued promises about releasing their web browser plugin and Web Start implementation as part of OpenJDK, but have so far failed to deliver.[41][citation needed] The only currently available free plugin and Web Start implementation are those provided by IcedTea.

[edit]IcedTea and inclusion in software distributions

To be able to bundle OpenJDK in Fedora and other free Linux distributions, OpenJDK needed to be buildable using only free software components. Due to the encumbered components in the class library and implicit assumptions within the build system that the JDK being used to build OpenJDK was a Sun JDK[why?], this was not possible. To achieve this goal, a project called IcedTea was started by Red Hat in June 2007.[42] It began life as an OpenJDK/GNU Classpath hybrid that could be used to bootstrap OpenJDK, replacing the encumbrances with code from GNU Classpath.[43][44]

On November 5, 2007, Red Hat signed both the Sun Contributor Agreement and the OpenJDK Community TCK License.[45] One of the first benefits of this agreement is tighter alignment with the IcedTea project, which brings together Fedora, the Linux distribution, and JBoss, the application server, technologies in a Linux environment. IcedTea is providing free software alternatives for the few remaining proprietary sections in the OpenJDK project.

In May 2008, the Fedora 9[37][46] and Ubuntu 8.04[47] distributions included IcedTea 6, based completely on free and open source code.[48] Fedora 9was the first version to ship with IcedTea6, based on the OpenJDK6 sources from Sun rather than OpenJDK7. It was also the first to use OpenJDK for the package name (via the OpenJDK trademark agreement) instead of IcedTea.[37]Ubuntu also first packaged IcedTea7[49] before later moving to IcedTea6. Packages for IcedTea6 were also created for Debian and included in lenny. On July 12, 2008, Debian accepted OpenJDK-6 in unstable,[50][51] and it is now in stable.[52] OpenJDK is also available on openSUSE,[53] Red Hat Enterprise Linux and RHEL derivatives such asCentOS.[54]

In June 2008, Red Hat announced that the packaged binaries for OpenJDK on Fedora 9, built using IcedTea 6, had passed the Technology Compatibility Kit tests and could claim to be a fully compatible Java 6 implementation.[55] In July 2009, an IcedTea 6 binary build for Ubuntu 9.04 passed all of the compatibility tests in the Java SE 6 JCK.[56]

Since August 2008, OpenJDK 7 is runnable on Mac OS X and other BSD variants.[57]

[edit]See also

[edit]References

  1. ^ http://download.java.net/openjdk/jdk6/promoted/b05/
  2. ^ "OpenJDK Legal Documents"Sun Microsystems.
  3. ^ Moving to OpenJDK as the official Java SE 7 Reference Implementation
  4. ^ Java Platform, Standard Edition 7 Reference Implementations
  5. ^ Schwartz, Jonathan (May 23, 2006). "Busy Week...". Sun Microsystems. Retrieved May 9, 2007.[dead link]
  6. ^ "Sun Opens Java" (OGG Theora). Sun Microsystems.[dead link]
  7. ^ "Sun CEO sets open source Java time frame - Announcement set for 30 to 60 days"InfoWorld. 2006-10-25. Retrieved 2011-12-22.
  8. ^ "Sun Opens Java". Sun Microsystems. November 13, 2006. Archived from the original on April 21, 2007. Retrieved May 9, 2007.
  9. ^ Stallman, Richard. "Free But Shackled—The Java Trap". Retrieved December 4, 2007.
  10. ^ http://www.sun.com/software/opensource/java/faq.jsp#b4
  11. ^ "Open JDK is here!". Sun Microsystems. May 8, 2007. Retrieved May 9, 2007.
  12. ^ Some encumbered code[clarification needed] remains in the JDK; Sun stated that it will continue to use such code in commercial releases until fully functional free and open source alternatives replace it.
  13. ^ Broad contributor agreement and TCK License pave way for a fully compatible, free and open source Java Development Kit for Red Hat Enterprise Linux
  14. ^ Porters Group
  15. ^ http://www.eyesbeyond.com/freebsddom/java/jdk16.html
  16. ^ http://landonf.bikemonkey.org/code/macosx/
  17. ^ New java for haiku team formed
  18. ^ James Gosling (October 2006). James Gosling on Open Sourcing Sun's Java Platform Implementations, Part 1. Interview with Robert Eckstein.
  19. ^ O'Hair, Kelly (December 12, 2007). "Mercurial OpenJDK Questions".
  20. ^ "Sun Microsystems Inc. Contributor Agreement".
  21. ^ "Regression Test Harness for the OpenJDK platform: jtreg". Retrieved August 26, 2008.
  22. ^ Tripp, Andy (July 16, 2007). "Classpath hackers frustrated with slow OpenJDK process". Retrieved April 20, 2008.
  23. ^ Kennke, Roman (September 29, 2008). "A small step for me". Retrieved October 19, 2008.[dead link]
  24. ^ Darcy, Joe (June 10, 2010). "Backporting changeset from 7 to 6 for bugfix".
  25. ^ "Oracle and IBM Collaborate to Accelerate Java Innovation Through OpenJDK"Oracle Corporation. Retrieved October 22, 2010.
  26. ^ Ryan Paul. "Java wars: IBM joins OpenJDK as Oracle shuns Apache Harmony"Ars Technica. Retrieved October 22, 2010.
  27. ^ Bob Sutor. "IBM joins the OpenJDK community, will help unify open source Java efforts". Retrieved October 22, 2010. "IBM will be shifting its development effort from the Apache Project Harmony to OpenJDK. For others who wish to do the same, we’ll work together to make the transition as easy as possible. IBM will still be vigorously involved in other Apache projects."
  28. ^ "Java for Mac OS X 10.6 Update 3 and 10.5 Update 8 Release Notes". October 20, 2010.
  29. ^ "Oracle and Apple Announce OpenJDK Project for Mac OS X"Business Wire. 2010-11-12. Retrieved 2010-11-12. "Oracle and Apple today announced the OpenJDK project for Mac OS X. Apple will contribute most of the key components, tools and technology required for a Java SE 7 implementation on Mac OS X, including a 32-bit and 64-bit HotSpot-based Java virtual machine, class libraries, a networking stack and the foundation for a new graphical client. OpenJDK will make Apple’s Java technology available to open source developers so they can access and contribute to the effort."
  30. ^ Mike Swingler (Apple) (2011-01-11). "Announcing: OpenJDK for Mac OS X source repository, mailing list, project home". OpenJDK. Retrieved 2010-11-12. "I'm very happy to let you know that today we made the first public contribution of code to the OpenJDK project for Mac OS X. This initial contribution builds on the hard work of the BSD port, and initially has the same functionality. Today's contribution simply modifies the build process to create universal binary, and produces a .jdk bundle which is recognized by Java Preferences and the JVM detection logic in Mac OS X."
  31. ^ Volker Simonis (SAP AG) (2011-07-14). "SAP joins the OpenJDK". OpenJDK. Retrieved 2010-11-12. "I'm really happy that as of today, SAP has signed the Oracle Contributor Agreement (OCA). This means that with immediate effect the SAP JVM developers can officially join the discussions on the various OpenJDK mailing lists and contribute patches and enhancements to the project."
  32. ^ "Didn't you promise to open source both JDK 6 and JDK 7 last November? What happened to JDK 6?". Sun Microsystems. Retrieved October 14, 2007. "Sun did make that promise, and we plan to keep it. But in the six months since the November 2006 announcement, it has become clear that doing this is far more complex than just changing the license and publishing the source code."
  33. ^http://weblogs.java.net/blog/robogeek/archive/2009/01/it_will_be_open.html
  34. ^ Darcy, Joe (February 11, 2008). "The code is coming! The code is coming!". Retrieved February 16, 2008. "At Sun we're making final preparations for the first source release for the OpenJDK 6 project. We plan to release a tarball of the source, along with matching binary plugs, by February 15, 2008."
  35. ^ Fitzsimmons, Thomas (May 18, 2007). "Plans for OpenJDK". Retrieved May 22, 2007.
  36. a b "OpenJDK 6 b10 source posted". May 30, 2008. Retrieved June 1, 2008.
  37. a b c Wade, Karsten (March 13, 2008). "OpenJDK in Fedora 9!". redhatmagazine.com. Retrieved April 5, 2008. "Thomas Fitzsimmons updated the Fedora 9 release notes source pages to reflect that Fedora 9 would ship with OpenJDK 6 instead of the IcedTea implementation of OpenJDK 7. Fedora 9 (Sulphur) is due to release in May 2008."
  38. ^ "Changes in OpenJDK7 b53". April 2, 2009. Retrieved September 5, 2009.
  39. ^ Herron, David (October 4, 2007). "Plans for OpenJDK". Retrieved October 9, 2007.
  40. ^ Kelly O'Hair (December 2010). "OpenJDK7 and OpenJDK6 Binary Plugs Logic Removed"Oracle Corporation. Retrieved 2011-11-25.
  41. ^ Darcy, Joe (June 8, 2009). "OpenJDK and the new plugin". Retrieved September 5, 2009.
  42. ^ Fitzsimmons, Thomas (June 8, 2007). "Credits". Retrieved June 8, 2007.
  43. ^ Andrew, Haley (June 7, 2007). "Experimental Build Repository at icedtea.classpath.org". Retrieved June 9, 2007.
  44. ^ Mark, Wielaard (June 7, 2007). "Experimental Build Repository at icedtea.classpath.org". Retrieved June 9, 2007.
  45. ^ "Red Hat and Sun Collaborate to Advance Open Source Java Technology"Red Hat. November 5, 2007. Retrieved November 6, 2007.
  46. ^ "Open Source Java Technology Debuts In GNU/Linux Distributions". Sun Microsystems. Retrieved May 2, 2008.
  47. ^ "openjdk-6 in Ubuntu". Retrieved April 19, 2008.
  48. ^ Reinhold, Mark (April 24, 2008). "There’s not a moment to lose!". Retrieved April 19, 2008.
  49. ^ "icedtea-java7 in Ubuntu". Retrieved April 19, 2008.
  50. ^ Topic, Dalibor (July 14, 2008). "QotD: Debian Overview of openjdk-6 source package". Retrieved July 15, 2008.
  51. ^ "Overview of openjdk-6 source package". debian.org. Retrieved July 15, 2008.
  52. ^ "Package: openjdk-6-jdk". debian.org. February 14, 2009. Retrieved February 16, 2009.
  53. ^ "Package: OpenJDK". opensuse.org. Retrieved June 1, 2009.[dead link]
  54. ^ "How to download and install prebuilt OpenJDK packages". Retrieved March 3, 2010.
  55. ^ Sharples, Rich (June 19, 2008). "Java is finally Free and Open".
  56. ^ Announcing OpenJDK 6 Certification for Ubuntu 9.04 (jaunty)
  57. ^ Fuller, Landon (August 19, 2008). "SoyLatte, Meet OpenJDK: OpenJDK 7 for Mac OS X". Retrieved August 22, 2008.

[edit]External links








JDK 7 The Platform 2011

  

NHN Business platform 웹플랫폼개발랩 문종호

2011년 7월 말 JDK 7이 정식으로 릴리스되었습니다. 비록 Lambda나 Jigsaw 같이 화제가 되었던 프로젝트는 JDK 8로 연기되어 김이 새긴 했지만, 무려 5년 만에 나오는 새 버전인 만큼 전세계 Java 개발자들의 이목이 집중되었습니다. 이 글에서는 JDK 7을 전체적으로 살펴보고, 주요 기능은 좀 더 심도 있게 알아보겠습니다.

  • 들어가며

  • OpenJDK

    Sun(현재 Oracle)이 JDK 7을 개발하기 시작할 때 이전과 다른 점이 하나 있었다. 그것은 바로 Sun이 JDK를 오픈소스화하기 위해 2007년 OpenJDK를 만들었다는 것이다. Sun은 저작권자가 오픈소스화를 거부한 일부 컴포넌트를 제외한 나머지 JDK 소스코드 전부를 OpenJDK에 제공했고, OpenJDK는 이를 기반으로 JDK 7 프로젝트를 시작했다. 즉, 누구나 OpenJDK의 소스코드 저장소에 접근하여 소스코드를 살펴볼 수 있으며, 의지와 능력만 있으면 개발에도 참여할 수 있다.

    그런데 한 가지 이상한 점이 있다. OpenJDK는 소스코드만 배포하고 바이너리는 배포하지 않는다. 앞에서 언급했듯이 일부 컴포넌트의 저작권자가 오픈소스화를 거부했기 때문이다. 그럼 JDK 7을 사용하려면 소스코드를 내려 받아 직접 빌드해야 하나? 다행히 그렇지는 않다.

    Java.net에는 또 하나의 JDK 7 프로젝트(이하, Oracle JDK 7)가 있다. Oracle JDK 7은 OpenJDK의 JDK 7 기반에 추가로 OpenJDK에 포함되지 않는 컴포넌트까지 모두 갖춘 프로젝트이다. 하지만 Oracle JDK 7은 오픈소스가 아니며, Oracle의 직원들만 개발에 참여할 수 있다. Oracle의 공식 JDK 7은 바로 이 프로젝트의 결과물이다.

  • Java SE 7, JDK 7, Java 7

    이야기가 나온 김에 한 가지 더 짚고 넘어가자. Java 7, Java SE 7, JDK 7 등의 용어가 혼용되는데 이들의 차이점은 무엇일까?

    Java SE는 Java Platform, Standard Edition의 약자로, Java Platform의 근간을 이루는 '명세(Specification)'를 가리킨다. JDK는 Java Development Kit의 약자로, 앞에서 말한 '명세'의 '구현체'를 가리킨다고 보면 된다. 즉, Java SE 7은 JSR-336로 규정된 Java SE의 7번째 명세를 가리키는 용어이고, JDK 7은 그 구현체, 이를테면 OpenJDK JDK 7, Oracle JDK 7과 같은 것을 가리키는 것이다.

    그런데 JDK 7은 Java SE 7이 확정되기 전에 개발되었다. OpenJDK에서 명세와 구현을 동시에 진행하고 그 결과가 JSR(Java Specification Request)에 반영되어 명세가 결정되는 순서로 진행되었던 것이다. 그래서인지 Java SE 7보다는 JDK 7이라는 용어가 훨씬 더 많이 사용되었다. 따라서 여기에서도 Java SE 7보다는 JDK 7이라는 용어를 사용하도록 하겠다.

    한편 Java는 다양한 의미로 사용되지만 엄밀히 말하면 버전을 붙여서 사용할 수 있는 용어는 아니다. 즉 Java 7은 정확한 표현이 아니다. 하지만 Java SE 7이나 JDK 7보다 발음하기 편하고, 그냥 Java 7이라고 부른다고 해서 무슨 의미인지 혼란스러워 할 사람도 없기 때문에 흔히 Java 7이라고 부르기도 하는 것이다.

  • Plan B

    그런데 JDK 7이 릴리스되기 전부터 JDK 8에 대한 이야기가 들려오기 시작했다. 어떻게 된 것일까?

    Java SE 6까지 Java SE는 약 2년을 주기로 메이저 버전이 릴리스되어 왔다. 그래서 Java SE 7도 Java SE 6이 릴리스된 지 약 2년 후, 그러니까 2008년 말이나 늦어도 2009년 중에는 릴리스될 것이라 생각되었다. 그러나 Oracle이 Sun을 인수하는 등 여러 일로 인해 JDK 7 개발은 자꾸 지연되었고, 이대로는 2012년에나 완성될 것이라고 예측하기도 했다. 결국 2010년 9월, Oracle의 Mark Reinhold는 마무리되어가고 있는 명세를 모아 2011년에 JDK 7으로 릴리스하고 나머지는 2012년 말에 릴리스할 JDK 8으로 미루자는 Plan B를 제안했다. 그리고 Oracle은 이 제안을 채택하여 2010년 JavaOne에서 공식적으로 Plan B 채택을 발표했다.

    JDK 8으로 미뤄진 프로젝트는 Project Coin의 일부와 Project Lambda, Project Jigsaw 등이다. Project Lambda는 Java 언어에 Closure를 도입하는 것으로 자바 언어의 표현력을 크게 높일 수 있는 반면 함수형 언어에 익숙하지 않은 개발자들을 혼란에 빠뜨릴 수 있다. Generics 이후 최대의, 어쩌면 Generics보다 더 큰 언어적 변화를 가져올 수 있는 프로젝트이다.

    Project Jigsaw는 JDK 클래스 라이브러리 자체를 모듈화하는 것을 목표로, Java 클래스들을 묶어 모듈을 구성할 수 있도록 하는 프로젝트이다. 여기서 모듈은 패키지나 JAR과는 다른 것으로, OSGi의 모듈과 비슷하다고 할 수 있다.

    이 두 프로젝트는 규모가 크고, 그만큼 많은 사람들의 관심을 끌고 있다. 이들에 비하면 JDK 7에 포함된 프로젝트는 미미해 보일 정도이다. 아쉽기는 하지만, 그래도 JDK 7에는 꽤 유용한 기능들이 남아 있다. 지금부터 JDK 7에서 만나볼 수 있는 기능들을 찬찬히 살펴보도록 하겠다.

  • JDK 7의 주요 기능

    JDK 7의 전체 기능은 JDK Features(http://openjdk.java.net/projects/jdk7/features/)에서 볼 수 있다. 여기에서는 중요한 기능들만 간단히 살펴보도록 하자.

  • JSR 292: Support for dynamically-typed languages (InvokeDynamic)

  • JVM(Java Virtual Machine)에서 동작하는 언어는 Java만이 아니다. 기존 언어가 JVM에서 동작하도록 구현한 JRuby, Jython 같은 언어도 있고, Groovy, Scala 같이 처음부터 JVM 기반으로 만들어진 언어도 있다. 그러나 JVM에는 아직 Java에 의존적인 부분이 있기 때문에 다른 언어, 특히 동적 타입 언어가 JVM에서 동작하는 데 걸림돌이 되는 부분이 있었다.

    InvokeDynamic은 이러 걸림돌을 제거하는 작업의 일환으로, JVM에서 동작하는 동적 타입 언어들의 효율성(바이너리 크기 등)과 성능 향상을 이끌어낼 것으로 보인다. 다만 동적 타입 언어의 제작자가 아닌 일반 개발자가 InvokeDynamic을 직접 사용할 일은 거의 없으므로 우리가 InvokeDynamic을 깊이 살펴볼 필요는 없을 것이다.

  • JSR 334: Small language enhancements (Project Coin)

  • Java 개발자들이 가장 직접적으로 큰 변화를 느낄 수 있는 부분이 바로 Project Coin이다. Project Coin은 Java 언어에 작은 변화를 주어서 개발자들의 가려운 곳을 긁어주자는 목적으로 시작됐으며, 구체적인 변화 내용에 대해서는 Oracle 내부 개발자뿐 아니라 누구라도 참여할 수 있도록 공개적으로 제안서를 모집했다. 그 결과 70여 개의 제안서를 받았고, 그 중 다음과 같은 내용을 JDK 7에 포함했다.

    • String in switch: switch 문에서 int와 Enum 외에 문자열도 사용할 수 있다.
    • Binary integral literals and underscores in numeric literals: 2진수 리터럴 표현이 가능해지며, 모든 숫자 리터럴에서 언더스코어(_)를 사용하여 가독성을 높일 수 있다.
    • Multi-catch and more precise rethrow: 하나의 catch 절에서 여러 타입의 예외를 처리할 수 있다.
    • Improved Type Inference for Generic Instance Creation: Generic 객체를 생성할 때 타입 파라미터를 일일이 기술하지 않아도 된다.
    • try-with-resources statement: try 절에서 사용되는 AutoClosable을 구현한 자원의 close() 메서드가 불리는 것을 보장하여 자원이 새는 것을 막는다.
    • Simplified Varargs Method Invocation: 가변 인자 메서드와 generic이 만나서 발생하는 경고(warning)를 해결할 수 없는 경우가 있다. 이 경고를 해결하는 방법을 제공한다.
  • JSR 203: More new I/O APIs for the Java platform (NIO.2)

  • java.io.File을 대체할 java.nio.Path가 추가되며, 파일시스템과 관련된 많은 유틸리티 API, 비동기 채널, 파일 속성 관련 API, 파일시스템 감시(watcher) 기능 관련 API 등 많은 API가 추가된다.

  • Concurrency and collections updates(jsr166y)

  • Fork/Join 프레임워크를 포함하여 Java 동시성(concurrency)과 관련된 클래스가 추가된다.

  • 기타

  • 그 밖에 한번 훑어볼 만한 기능은 다음과 같다.

    • Upgrade class-loader architecture: 클래스 로더의 의존 관계에 사이클이 존재하면 데드락(deadlock)이 발생하는 문제를 피하도록 수정되었다.
    • Locale enhancement: Java의 로캘(locale)은 현재 IETF BCP 47로 대체된 IETF RFC 1766 기반이다. 따라서 Java의 로캘을 IETF BCP 47 기반으로 변경했다.
    • Unicode 6.0: Unicode 6.0을 지원한다.
    • Enhanced JMX Agent and MBeans: JRockit에서 포팅된 기능으로, 방화벽 내의 MBean 서버에 접근할 수 있게 하고, VM에 대해 더 많은 정보를 제공하는 MBean을 제공한다.
    • JDBC 4.1: JDBC 4.1로 업그레이드된다.
    • Update the XML stack: JAXP, JAXB, JAX-WS의 최신 버전으로 업그레이드된다.

     

    이 글에서는 이 중 Project Coin과 NIO.2, Fork/Join 프레임워크에 대해서 한층 더 깊이 살펴보도록 한다.

  • Project Coin

    Project Coin은 JDK 7의 새 기능들 중 우리에게 가장 직접적으로 영향을 줄 기능이다. 그런데 갑자기 웬 동전일까? 아는 사람도 많겠지만, 영어 사전을 찾아보면 동사 coin은 다음과 같은 뜻이다.

  • (새로운 낱말, 어구를) 만들다
  • (주화를) 주조하다
  • Project Coin에서 coin은 첫 번째 의미로 사용된다. Java의 문법에 새로운 뭔가를 만들어 넣는다는 것이다. 그래도 의문은 남는다. Project Lamda나 Project Jigsaw 등 다른 프로젝트들은 이름이 그 프로젝트의 내용을 나타내는데, Project Coin은 단지 '새로 만든다'라는 의미뿐이다. 이렇게 된 이유는 Project Coin의 시작과 진행 과정에서 찾을 수 있다.

    Project Coin은 2008년 12월, 프로젝트 리더인 Joseph D. Darcy의 블로그 게시글에서 시작되었다. Sun(현재 Oracle)이 JDK 7에 '작은 언어 변화'를 포함시키기로 했는데, 구체적으로 어떤 변화를 줄 것인지는 공개적으로 제안서를 받아서 선정하겠다는 이야기였다. 그리고 여기에서 말하는 '작은 언어 변화'가 구체적으로 어떤 것인지, 제안서를 어떻게 써야 하는지 안내하는 게시글이 이어졌다. 그리고 2009년 2월 27일, Project Coin의 메일링리스트가 개설되었고 3월 30일까지 약 한 달 동안 70여 개의 제안서가 제출되었다. 같은 해 8월, 이 중 Project Coin에 포함될 제안서들이 확정되었다.

    이처럼 Project Coin은 구체적으로 어떤 변화를 줄 것인지 정해놓고 시작한 것이 아니라 대중으로부터 제안을 받아 취합하는 형태로 진행된 프로젝트였기 때문에 이렇게 약간은 막연한 이름을 갖게 된 것이다.

    이후 JDK 7의 진행이 지지부진해지면서 Project Coin도 함께 지지부진하게 진행되었다. 그리고 JDK 7과 JDK 8의 분리가 결정되면서 Project Coin도 JDK 7과 JDK 8에 포함될 것들로 구분했다. 다행히 JDK 8으로 연기된 기능은 Language support for collections 하나뿐이고, 나머지 기능들은 JSR 334에서 공식적인 절차에 따라 명세가 확정되었다.

    그럼 이제부터 Project Coin의 기능들을 간단한 것부터 순서대로 살펴보도록 하겠다.

  • Binary integrals and underscores in numeric literals

  • 이 기능은 두 가지 내용을 담고 있다. 하나는 16진수 리터럴처럼 2진수 리터럴도 사용할 수 있게 하는 것이다. 16진수가 0x 또는 0X로 시작하는 것처럼 2진수는 0b 또는 0B로 시작한다.

    1
    int x = 0b0110;

    다른 하나는 가독성을 높이기 위해 숫자 리터럴 중간에 언더스코어(_)를 넣을 수 있다는 것이다. 예를 들어 다음과 같은 상수를 보자.

    1
    2
    private static final long TIMEOUT = 3600000;
    private static final int BINARY_VALUE = 0b1001011011000011;

    한눈에 파악하기 쉽지 않다. JDK 7에서는 이를 다음과 같이 쓸 수 있다.

    1
    2
    private static final long TIMEOUT = 3600_000;
    private static final int BINARY_VALUE = 0b1001_0110_1100_0011;

    언더스코어는 숫자 사이 어디에든 넣을 수 있고, 언더스코어를 둘 이상 붙여서 쓸 수도 있다.

  • Strings in switch

  • 지금까지 switch 문에는 int와 Enum 타입만 사용할 수 있었지만 JDK 7부터는 String도 사용할 수 있다. 번잡한 if ... else ... 체인 대신 깔끔하게 switch 문을 사용할 수 있게 된 것이다. 다음은 String을 사용한 switch 문의 예이다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void handle(String code, Something arg) {
    switch (code) {
    case "INSERT":
    handleInsert(arg);
    break;
    case "DELETE":
    handlerDelete(arg);
    break;
    default:
    throw new IllegalArgumentException();
    }
    }

    만약 switch 문에 null 값이 들어오면(위 예제에서 code의 값이 null이면) NullPointerException이 발생한다.

    문법적으로 더 설명할 만한 것은 없으나 Strings in switch가 어떻게 구현되는지 간단히 알아보자. Project Coin의 목표는 JVM 명세는 변경하지 않으면서 변화를 주는 것이다. 즉 Strings in switch는 자바 바이트코드 수준에서 지원되는 것이 아니라 컴파일러가 적절한 코드로 변환하는 것이다. 그런데 Project Coin은 이런 변환 과정이 어떻게 이루어지는지, 어떤 코드로 변환하는지는 언급하지 않고 있다. 컴파일러에 따라 최적의 방식으로 구현할 것이며, 우리는 구체적인 내용은 알 것 없이 그냥 쓰면 된다.

    String을 사용할 수 있다면 그냥 모든 객체를 다 사용할 수 있게 하면 안 되는지 궁금해하는 사람들도 있을 것이다. 하지만 그렇게 만만한 일은 아니다. String을 지원하는 것은 자바 명세에 한 줄을 추가하는 것으로 끝났지만, Object를 지원하려면 훨씬 많이 변경해야 한다. 게다가 switch 문에서 굳이 Object를 사용해야 하는 경우가 있을까?

  • Improved Type Inference for Generic Instance Creation (diamond)

  • 이 기능은 많은 사람들이 반길 만한 기능이다. 기존에 작성했던 다음과 같은 코드를 보자.

    1
    2
    List<map <string,="" object="">> mapList = new ArrayList<map <string,="" object="">>();
     </map></map>

    위 코드를 다음과 같이 작성할 수 있게 되었다.

    1
    2
    List<map <string,="" object="">> mapList = new ArrayList<>();
     </map>

    즉, generic 객체를 생성할 때, 타입 파라미터를 명시하지 않아도, 컴파일러가 추론해서 자동으로 채워주는 기능이다. 물론, 모든 상황에서 가능한 것은 아니지만 OpenJDK, Tomcat, NetBeans 소스를 대상으로 테스트한 결과 약 90%정도는 정확하게 추론해냈다고 한다.

    일반적으로 객체를 생성하는 경우는 다음과 같이 네 가지로 나눌 수 있으며, 네 경우 모두 diamond를 사용할 수 있다.

    • 변수 선언
    1
    2
    List<map <string,="" object="">> mapList = new ArrayList<>();
     </map>
    • 변수 대입
    1
    2
    3
    4
    List<map <string,="" object="">> mapList;
    ……
    mapList = new ArrayList<>();
     </map>
    • 메서드 호출
    1
    2
    3
    4
    5
    6
    public void doSomething(List<map <string,="" object="">> map) {
    ……
    }
      
    doSomething(new ArrayList<>());
     </map>
    • 반환
    1
    2
    3
    4
    5
    public List<map <string,="" object="">> doSomething() {
    ……
    return new ArrayList<>();
    }
     </map>

    그러나 항상 이 기능을 사용하는 것이 바람직하지는 않을 것 같다. 메서드를 호출할 때, 특히 타입 파라미터를 가진 메서드를 호출할 때에는 상황이 복잡해질 수 있고, 최악의 경우 컴파일러가 추론에 실패하여 엉뚱한 타입을 집어넣거나 아예 컴파일 에러가 발생할 수도 있다. 이때에는 뭐가 잘못된 것인지 상황을 분석하기도 쉽지 않다고 한다.

    하지만 변수 선언이나 대입의 경우에는 귀찮은 중복 코딩을 많이 줄여줄 유용한 기능이니 적극적으로 사용하길 권장한다.

  • Simplified Varargs Method Invocation

  • 이 기능은 매우 간단하지만 왜 필요한지 이해하기는 쉽지 않다. 바로 Generics가 얽힌 문제이기 때문이다. 한 문장으로 설명하자면 "비정형적인(non-reifiable) varargs 파라미터를 가지는 메서드의 varargs 파라미터에 비정형적인 타입의 값을 전달하여 호출하면 반드시 경고가 발생하는데, 이를 없앨 수 있는 방법을 제공하겠다"라는 것이다.

    1
    2
    3
    4
    Map<string ,="" object=""> foo = new HashMap<string ,="" object="">();
    Map<string ,="" object=""> bar = new HashMap<string ,="" object="">();
    List<map <string,="" object="">> result = Arrays.asList(foo, bar); // 경고 발생
     </map></string></string></string></string>

    세 번째 줄에서 'Type safety : A generic array of Map<String, Object> is created for a varargs parameter'라는 경고가 발생한다. 무엇이 문제인지 알아보기 위해 asList() 메서드를 살펴보자.

    1
    2
    3
    4
    public static <t> List<t> asList(T... a) {
    return new ArrayList<t>(a);
    }
     </t></t></t>

    아무리 봐도 잘못된 부분은 없다. 하지만 asList()를 호출하는 코드에 @SuppressWarnings("unchecked")를 삽입하는 것 외에는 저 경고를 제거할 수 있는 방법이 없다.

    이 문제는 컴파일러가 varargs 메서드 파라미터를 배열로 변환하기 때문에 발생한다. asList()는 내부적으로 다음과 같이 변환된다.

    1
    2
    List<map <string,="" object="">> result = Arrays.asList(new Map<string ,="" object=""> [] { foo, bar });
     </string></map>

    실제로 이 코드를 직접 작성하여 컴파일하면 new Map<String, Object>[]에서 에러가 발생하고 컴파일이 중지된다. Java Generics에서 사용하는 type eraser 때문에 형 안전(type safe)하지 않은 상황이 발생할 가능성이 있어서 generic 배열을 생성할 수 없도록 했기 때문이다. 그런데 varargs 메서드를 처리할 때에는 컴파일러가 직접 이렇게 변환하고는 경고를 한다. 그러면 다음과 같은 문제가 발생한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public static <t> ValueHolder<t>[] doBadThing(ValueHolder<t>... values) {
    Object[] objs = values;
    objs[0] = new ValueHolder<integer>(10);
    return values;
    }
      
    public static void main(String[] args) {
    ValueHolder<string>[] result = doBadThing(new ValueHolder<string>("foo"), new ValueHolder<string>("bar"));
      
    for (ValueHolder<string> holder : result) {
    String value = holder.getValue(); // ClassCastException 발생
    System.out.println(value);
    }
    }
      
    public static class ValueHolder<t> {
    private T value;
      
    public ValueHolder(T value) {
    this.value = value;
    }
      
    public T getValue() {
    return value;
    }
    }
     </t></string></string></string></string></integer></t></t></t>

    위의 코드를 컴파일하면 경고만 하나 발생하고 컴파일이 완료된다. 그런데 이를 실행시키면 ClassCastException이 발생한다. 이는 doBadThing()에서 values에 ValueHolder<Integer>를 넣었기 때문이다. 그리고 컴파일러가 이를 막지 못한 것은 type eraser에 의해 values의 타입 파라미터 정보가 지워졌기 때문이다. 즉, 런타임에 VM이 values가 ValueHolder의 배열이라는 것만 알 뿐 ValueHolder<String> 배열이라는 것은 알 수 없다. 마찬가지로 ValueHolder<Integer>를 생성하더라도 런타임 시에는 이것이 ValueHolder로만 취급된다. 따라서 JVM이 보기엔 아무런 문제가 없다.

    위 코드는 JVM에게 아래와 같은 코드로 보인다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public static ValueHolder[] doBadThing(ValueHolder[] values) {
    Object[] objs = values;
    objs[0] = new ValueHolder (10);
    return values;
    }
      
    public static void main(String[] args) {
    ValueHolder[] result = doBadThing(new ValueHolder[] { ValueHolder ("foo"), new ValueHolder ("bar")});
      
    for (ValueHolder holder : result) {
    String value = (String) holder.getValue(); // ClassCastException 발생
    System.out.println(value);
    }
    }
      
    public static class ValueHolder {
    private Object value;
      
    public ValueHolder(Object value) {
    this.value = value;
    }
      
    public Object getValue() {
    return value;
    }
    }

    이제 어떤 문제가 발생할 수 있는지 알았다. 그런데 저런 일이 얼마나 일어나겠는가? 일부러 문제를 일으키려고 작정하지 않은 이상 이런 코드를 작성할 일은 거의 없다. 처음에 예를 든 Arrays.asList()에서도 이런 문제가 발생할 일은 전혀 없다. 그럼에도 불구하고 우리는 계속 무의미한 경고를 보지 않을 수 없었다.

    JDK 7에서는 이러한 문제를 해결하기 위해 다음과 같은 조치를 취했다.

    • non-reifiable한 varargs를 가지는 메서드의 호출뿐만 아니라 선언에도 경고를 발생시킨다.
    • 해당 메서드에 아무런 문제가 없다면 메서드의 선언에 @SafeVarargs 어노테이션을 달 수 있다. 이 어노테이션을 달면 메서드의 선언과 호출에 경고가 발생하지 않는다.

    다음은 @SafeVarargs의 사용 예제이다. 이 메서드를 호출하는 코드에는 경고가 발생하지 않는다.

    1
    2
    3
    4
    5
    6
    7
    @SafeVarargs
    public static <t> void addAll(List<t> list, T... items) {
    for (T item : items) {
    list.add(item);
    }
    }
     </t></t>

    @SafeVarargs를 아무데나 붙일 수 있는 것은 아니다. 다음 조건을 만족시키지 않는 메서드에 @SafeVarargs를 사용하면 컴파일 에러가 발생한다.

    • varargs 메서드여야 한다
    • final 메서드나 static 메서드여야 한다.

    또한, 명세에서는 다음과 같은 메서드에 @SafeVarargs를 달면 컴파일러가 경고를 발생시키도록 권장하고 있다.

    • varargs 파라미터가 reifiable 타입인 경우
    • 위 예시 코드의 doBadThing()에서처럼 varargs 파라미터를 다른 변수에 대입하는 등 메서드에서 잠재적으로 문제의 가능성이 있는 연산을 수행하는 경우

    당연히 JDK 7의 라이브러리에는 @SafeVarargs가 적용되어 있다. 다음은 @SafeVarargs가 적용된 메서드이다.

    • public static <T> List<T> java.util.Arrays.asList(T... a)
    • public static <T> boolean java.util.Collections.addAll(Collection<? super T> c, T... elements)
    • public static <E extends Enum<E>> java.util.EnumSet<E> EnumSet.of(E first, E... rest)
    • protected final void javax.swing.SwingWorker.publish(V chunks)
  • Multi-catch and more precise rethrow

  • 이제 남은 두 가지 기능은 모두 try/catch 절과 관련된 것이다. 그 중에 Multi-catch and more precise rethrow는 두 가지 내용을 담고 있는데, 이는 어떤 한 가지 문제 상황을 해결하기 위한 것이다. 다음 예제를 통해 어떠한 문제인지 살펴보도록 하자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void someMethod() throws FooException, BarException {
    try {
    canThrowFooException();
    canThrowBarException();
    } catch (FooException e) {
    logger.log(e, e);
    throw e;
    } catch (BarException e) {
    logger.log(e, e);
    throw e;
    }
    }

    someMethod()는 canThrowFooException()과 canThrowBarException()을 호출하며, 이 메서드들은 각각 FooException과 BarException을 던진다. 이들이 예외를 던지면 someMethod()는 이를 잡아 로그를 남긴 후 다시 던진다.

    그런데 FooException과 BarException에 대한 catch 절이 완전히 동일하다. 중복을 줄이기 위해서 FooException과 BarException을 한꺼번에 처리할 수 있다면 좋을 것이다. 그래서 JDK 7에서는 다음과 같이 하나의 catch 절에서 여러 타입의 예외를 처리할 수 있는 multi catch 기능을 제공한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void someMethod() throws FooException, BarException {
    try {
    canThrowFooException();
    canThrowBarException();
    } catch (FooException | BarException e) {
    logger.log(e, e);
    throw e;
    }
    }

    이때 e는 FooException과 BarException이 공통으로 구현한 모든 타입, 즉 공통의 조상 클래스를 상속받고 두 예외가 공통으로 구현한 인터페이스를 구현한 타입으로 취급받는다. 예를 들어 FooException과 BarException이 다음과 같이 선언되었다면 위 코드의 예외 파라미터 e는 ParentException를 상속받고 SomeInterface를 구현한 타입으로 취급된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class ParentException {
    public void parentMethod() {
    //……
    }
    }
      
    public interface SomeInterface {
    void someMethod();
    }
      
    public interface AnotherInterface {
    void anotherMethod();
    }
      
    public FooException extends ParentException implements SomeInterface, AnotherInterface {
    // ……
    }
      
    public BarException extends ParentException implements SomeInterface {
    // ……
    }

    이렇게 multi catch에 사용된 파라미터 e는 final로 선언되지 않았어도 암묵적으로 final로 취급된다. 물론 명시적으로 final로 선언해도 되지만 스타일상의 이슈로 final을 쓰지 않을 것을 권장하고 있다. 사실 예외 파라미터에 다른 값을 대입할 일은 거의 없기 때문에 문제가 되지는 않을 것이다.

    multi catch와 관련한 또 하나의 제약 사항은 하나의 multi catch 절에서 처리하는 타입들 간에 부모 자식 관계가 존재하면 안 된다는 것이다. 예를 들어 다음과 같이 FooException과 그 부모 클래스인 ParentException을 함께 잡는 코드는 컴파일 에러가 발생한다. 하지만 이 역시, ParentException 하나만 잡으면 당연히 FooException도 같이 잡히기 때문에 굳이 둘을 같이 처리할 필요는 없으므로 별로 문제가 될 만한 제약은 아니다.

    1
    2
    3
    4
    5
    6
    7
    try {
    canThrowFooException();
    canThrowBarException();
    } catch (ParentException | FooException e) { // 컴파일 에러
    logger.log(e, e);
    throw e;
    }

    다시 처음에 제기했던 문제로 돌아가 보자. 사실 multi catch 없이 코드 중복을 막을 수 있는 방법도 있다. 다음 코드를 보자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void someMethod() throws Exception {
    try {
    canThrowFooException();
    canThrowBarException();
    } catch (Exception e) {
    logger.log(e, e);
    throw e;
    }
    }

    이렇게 하나의 catch 절에서 모든 예외를 잡으면 된다. 그런데 여기에서 새로운 문제가 발생한다. 이렇게 모든 예외를 잡아서 다시 던지려면 someMethod()도 예외를 던지도록 선언해야 한다. 문제는, 누가 봐도 FooException과 BarException 밖에 나올 수 없는데 컴파일러는 그냥 catch절만 보고 throws Exception을 선언해야 한다고 판단해 버린다는 것이다.

    JDK 7에서는 바로 more precise rethrow로 이 문제를 해결했다. 이제 Java 컴파일러는 catch 절에서 다시 예외를 던질 때 다음과 같이 그 예외의 타입을 결정한다. catch 절에서 사용된 예외 파라미터가 다음 조건을 만족하면 위의 코드에서 someMethod()는 FooException과 BarException을 던진다고 선언할 수 있다.

    • final이거나 effectively final이다. effectively final은 JDK 7에서 추가된 개념으로, final로 선언되지 않았지만 한 번 값이 할당된 후 변경되는 일이 없는 경우를 가리킨다.
    • try 절에서 발생할 수 있다.
    • 앞선 catch 절에서 잡은 것이 아니다.
    • 예외 파라미터에 대입할 수 있다.

    다음 예시에서 canThrowWhat()이 어떤 예외를 던진다고 선언해야 하는지, 즉 메서드 본문의 두 번째 catch 절에서 던지는 예외가 어떤 타입인지 결정되는 과정을 통해 이 규칙이 어떻게 적용되는지 살펴보겠다. 앞선 예시들에서 본 것처럼 canThrowFooException()과 canThrowBarException()은 각각 FooException과 BarException을 던지며, FooException과 BarException은 ParentException을 상속받는다. canThrowAnotherException()은 AnotherException을 던지며, AnotherException은 FooException, BarException, ParentException과는 아무런 관계가 없고 Exception을 직접 상속받는 예외이다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public void canThrowWhat() throws ??? {
    try {
    canThrowFooException();
    canThrowBarException();
    canThrowAnotherException();
    } catch (FooException e) {
    // ……
    } catch (ParentException e) {
    System.out.println(e);