참고 : 저는 이 가이드의 버전 2를 작업 중이며 여러분의 도움이 필요합니다! 이 양식을 사용하여 다음 버전에 포함되어야 할 내용에 대한 피드백을 보내주세요. 감사해요!
Java는 가장 인기 있는 프로그래밍 언어 중 하나이지만 이를 즐겨 사용하는 사람은 없는 것 같습니다. 글쎄요, Java는 실제로 괜찮은 프로그래밍 언어입니다. 그리고 최근 Java 8이 출시되었기 때문에 저는 Java를 더 잘 사용할 수 있도록 라이브러리, 사례 및 도구 목록을 작성하기로 결정했습니다. "Better"는 주관적이기 때문에 한꺼번에 다 사용하려고 하기보다는 자신에게 와 닿는 부분을 골라서 사용하는 것을 추천해 드립니다. 추가 사항을 제안하는 풀 요청을 자유롭게 제출해 주세요.
이 글은 원래 제 블로그에 게시된 글입니다.
다른 언어로 읽어 보세요: 영어, 简体中文
전통적으로 Java는 매우 장황한 엔터프라이즈 JavaBean 스타일로 프로그래밍되었습니다. 새로운 스타일은 훨씬 더 깔끔하고 정확하며 눈에도 편합니다.
프로그래머로서 우리가 하는 가장 간단한 일 중 하나는 데이터를 전달하는 것입니다. 이를 수행하는 전통적인 방법은 JavaBean을 정의하는 것입니다.
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
이것은 장황하고 낭비적이다. IDE가 자동으로 이 코드를 생성하더라도 낭비입니다. 그러니 이러지 마세요.
대신, 나는 단지 데이터만 보유하는 클래스를 작성하는 C 구조체 스타일을 선호합니다.
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
이는 코드 줄 수가 절반으로 줄어든 것입니다. 또한 이 클래스는 확장하지 않는 한 불변이므로 변경할 수 없다는 것을 알고 있으므로 더 쉽게 추론할 수 있습니다.
쉽게 수정할 수 있는 Map 또는 List와 같은 개체를 저장하는 경우 대신 ImmutableMap 또는 ImmutableList를 사용해야 합니다. 이에 대해서는 불변성에 대한 섹션에서 설명합니다.
구조체를 빌드하려는 다소 복잡한 개체가 있는 경우 빌더 패턴을 고려하세요.
객체를 구성할 정적 내부 클래스를 만듭니다. 이는 변경 가능한 상태를 사용하지만 빌드를 호출하자마자 변경 불가능한 객체를 방출합니다.
더 복잡한 DataHolder 가 있다고 상상해 보세요. 이를 위한 빌더는 다음과 같습니다.
public class ComplicatedDataHolder {
public final String data ;
public final int num ;
// lots more fields and a constructor
public static class Builder {
private String data ;
private int num ;
public Builder data ( String data ) {
this . data = data ;
return this ;
}
public Builder num ( int num ) {
this . num = num ;
return this ;
}
public ComplicatedDataHolder build () {
return new ComplicatedDataHolder ( data , num ); // etc
}
}
}
그런 다음 사용하려면 다음을 수행하십시오.
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
빌더의 더 나은 예는 다른 곳에 있지만 이것이 어떤 것인지 맛보게 해 줄 것입니다. 이는 우리가 피하려고 했던 많은 상용구로 끝나지만 불변의 객체와 매우 유연한 인터페이스를 제공합니다.
빌더 개체를 직접 만드는 대신 빌더를 생성하는 데 도움이 될 수 있는 많은 라이브러리 중 하나를 사용하는 것이 좋습니다.
불변 객체를 수동으로 많이 생성하는 경우 주석 프로세서를 사용하여 인터페이스에서 자동으로 객체를 생성하는 것을 고려해 보세요. 이는 상용구 코드를 최소화하고 버그 가능성을 줄이며 불변성을 촉진합니다. 일반적인 Java 코딩 패턴과 관련된 몇 가지 문제에 대한 흥미로운 토론은 이 프레젠테이션을 참조하세요.
훌륭한 코드 생성 라이브러리로는 불변 라이브러리, Google의 자동 값 및 Lombok이 있습니다.
확인된 예외는 주의해서 사용해야 합니다. 이는 사용자가 많은 try/catch 블록을 추가하고 예외를 자체적으로 래핑하도록 강제합니다. 대신 예외가 RuntimeException을 확장하도록 만드는 것이 더 좋습니다. 이를 통해 사용자는 예외가 매번 발생하도록 처리/선언하도록 강요하여 코드를 오염시키는 대신 원하는 방식으로 예외를 처리할 수 있습니다.
한 가지 멋진 방법은 메서드의 throws 선언에 RuntimeExceptions를 넣는 것입니다. 이는 컴파일러에 영향을 미치지 않지만 문서를 통해 이러한 예외가 발생할 수 있음을 사용자에게 알립니다.
이는 Java 섹션이라기보다는 소프트웨어 엔지니어링 섹션에 가깝지만 테스트 가능한 소프트웨어를 작성하는 가장 좋은 방법 중 하나는 DI(종속성 주입)를 사용하는 것입니다. Java는 OO 설계를 강력히 권장하므로 테스트 가능한 소프트웨어를 만들려면 DI를 사용해야 합니다.
Java에서는 일반적으로 Spring Framework를 사용하여 이 작업을 수행합니다. 코드 기반 연결 또는 XML 구성 기반 연결이 있습니다. XML 구성을 사용하는 경우 XML 기반 구성 형식으로 인해 Spring을 과도하게 사용하지 않는 것이 중요합니다. XML에는 논리나 제어 구조가 전혀 없어야 합니다. 종속성만 주입해야 합니다.
Spring을 사용하는 것에 대한 좋은 대안은 Google과 Square의 Dagger 라이브러리 또는 Google의 Guice입니다. 그들은 Spring의 XML 구성 파일 형식을 사용하지 않고 대신 주석과 코드에 주입 논리를 넣습니다.
가능하면 null을 사용하지 마십시오. 대신 빈 컬렉션을 반환해야 하는 경우 null 컬렉션을 반환하지 마세요. null을 사용하려면 @Nullable 주석을 고려하세요. IntelliJ IDEA에는 @Nullable 주석이 기본적으로 지원됩니다.
컴퓨터 과학의 최악의 실수에서 null을 사용하지 말아야 하는 이유에 대해 자세히 알아보세요.
Java 8을 사용하는 경우 뛰어난 새 Optional 유형을 사용할 수 있습니다. 값이 존재할 수도 있고 존재하지 않을 수도 있는 경우 다음과 같이 Optional 클래스로 래핑하십시오.
public class FooWidget {
private final String data ;
private final Optional < Bar > bar ;
public FooWidget ( String data ) {
this ( data , Optional . empty ());
}
public FooWidget ( String data , Optional < Bar > bar ) {
this . data = data ;
this . bar = bar ;
}
public Optional < Bar > getBar () {
return bar ;
}
}
이제 데이터는 결코 null이 아니지만 bar가 존재할 수도 있고 존재하지 않을 수도 있다는 것이 분명해졌습니다. Optional 에는 isPresent 와 같은 메소드가 있는데, 이는 단지 null을 확인하는 것과 크게 다르지 않은 것처럼 느낄 수 있습니다. 하지만 다음과 같은 명령문을 작성할 수 있습니다.
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
null을 확인하는 경우 체인으로 연결된 것보다 훨씬 낫습니다. Optional 사용의 유일한 단점은 표준 라이브러리가 좋은 Optional 지원을 제공하지 않으므로 null 처리가 여전히 필요하다는 것입니다.
달리 만들 이유가 없는 한 변수, 클래스 및 컬렉션은 변경할 수 없어야 합니다.
final을 사용하여 변수를 불변으로 만들 수 있습니다.
final FooWidget fooWidget ;
if ( condition ()) {
fooWidget = getWidget ();
} else {
try {
fooWidget = cachedFooWidget . get ();
} catch ( CachingException e ) {
log . error ( "Couldn't get cached value" , e );
throw e ;
}
}
// fooWidget is guaranteed to be set here
이제 fooWidget이 실수로 재할당되지 않도록 보장할 수 있습니다. final 키워드는 if/else 블록 및 try/catch 블록과 함께 작동합니다. 물론, fooWidget 자체가 불변이 아니라면 쉽게 변경할 수 있습니다.
컬렉션은 가능할 때마다 Guava ImmutableMap, ImmutableList 또는 ImmutableSet 클래스를 사용해야 합니다. 여기에는 동적으로 빌드한 다음 빌드 메소드를 호출하여 불변으로 표시할 수 있는 빌더가 있습니다.
불변 필드를 선언하고( final 을 통해) 불변 컬렉션을 사용하여 클래스를 불변으로 만들어야 합니다. 선택적으로 클래스 자체를 최종 으로 만들어 확장 및 변경이 불가능하도록 만들 수 있습니다.
Util 클래스에 많은 메서드를 추가하는 경우 주의하세요.
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
처음에는 이러한 클래스가 매력적으로 보입니다. 그 안에 포함된 메서드가 실제로 어느 한 곳에 속하지 않기 때문입니다. 따라서 코드 재사용이라는 이름으로 여기에 모두 넣습니다.
치료법은 질병보다 더 나쁩니다. 이러한 클래스를 자신이 속한 곳에 배치하고 적극적으로 리팩터링하십시오. 클래스, 패키지 또는 라이브러리의 이름을 "MiscUtils" 또는 "ExtrasLibrary"와 같이 너무 일반적인 이름으로 지정하지 마십시오. 이는 관련 없는 코드를 거기에 덤핑하도록 권장합니다.
형식화는 대부분의 프로그래머가 생각하는 것보다 훨씬 덜 중요합니다. 일관성은 당신이 자신의 기술에 관심을 갖고 있다는 것을 보여주고 다른 사람들이 읽는 데 도움이 됩니까? 전적으로. 그러나 if 블록에 공백을 추가하여 "일치"하도록 하루를 낭비하지 마십시오.
코드 형식 지정 가이드가 꼭 필요한 경우 Google의 Java 스타일 가이드를 적극 권장합니다. 해당 가이드의 가장 중요한 부분은 프로그래밍 실습 섹션입니다. 확실히 읽어볼 가치가 있습니다.
사용자가 접하는 코드를 문서화하는 것이 중요합니다. 이는 예제를 사용하고 변수, 메소드 및 클래스에 대한 합리적인 설명을 사용하는 것을 의미합니다.
이에 따른 결과는 문서화할 필요가 없는 것은 문서화하지 않는다는 것입니다. 논쟁이 무엇인지에 대해 말할 것이 없거나 그것이 명백하다면 문서화하지 마세요. 상용구 문서는 문서가 전혀 없는 것보다 나쁩니다. 사용자가 문서가 있다고 생각하도록 속이기 때문입니다.
Java 8에는 멋진 스트림과 람다 구문이 있습니다. 다음과 같은 코드를 작성할 수 있습니다.
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
대신에:
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
이를 통해 더 읽기 쉽고 유창한 코드를 작성할 수 있습니다.
Java를 올바르게 배포하는 것은 약간 까다로울 수 있습니다. 현재 Java를 배포하는 방법에는 두 가지 주요 방법이 있습니다. 즉, 프레임워크를 사용하거나 보다 유연한 자체 개발 솔루션을 사용하는 것입니다.
Java 배포가 쉽지 않기 때문에 도움이 될 수 있는 프레임워크가 만들어졌습니다. 가장 좋은 두 가지는 Dropwizard와 Spring Boot입니다. Play 프레임워크도 이러한 배포 프레임워크 중 하나로 간주될 수 있습니다.
그들 모두는 코드를 외부로 내보내는 데 대한 장벽을 낮추려고 노력합니다. Java를 처음 사용하거나 작업을 빠르게 완료해야 하는 경우 특히 유용합니다. 단일 JAR 배포는 복잡한 WAR 또는 EAR 배포보다 쉽습니다.
그러나 다소 융통성이 없고 자기 주장이 강할 수 있으므로 프로젝트가 프레임워크 개발자의 선택에 맞지 않으면 보다 수동적인 구성으로 마이그레이션해야 합니다.
좋은 대안 : Gradle.
Maven은 여전히 테스트를 빌드, 패키징 및 실행하는 표준 도구입니다. Gradle과 같은 대안이 있지만 Maven과 동일하게 채택되지는 않습니다. Maven을 처음 사용하는 경우 Maven by 예제로 시작해야 합니다.
나는 사용하려는 모든 외부 종속성을 포함하는 루트 POM을 갖고 싶습니다. 다음과 같이 보일 것입니다. 이 루트 POM에는 외부 종속성이 하나만 있지만 제품이 충분히 크다면 수십 개가 있을 것입니다. 루트 POM은 버전 제어에서 자체적으로 프로젝트여야 하며 다른 Java 프로젝트처럼 릴리스되어야 합니다.
모든 외부 종속성 변경에 대해 루트 POM에 태그를 지정하는 것이 너무 많다고 생각한다면 프로젝트 간 종속성 오류를 추적하는 데 일주일을 낭비하지 않은 것입니다.
모든 Maven 프로젝트에는 루트 POM과 모든 버전 정보가 포함됩니다. 이렇게 하면 회사에서 선택한 각 외부 종속성 버전과 올바른 Maven 플러그인을 모두 얻을 수 있습니다. 외부 종속성을 가져와야 하는 경우 다음과 같이 작동합니다.
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
내부 종속성을 원하는 경우 각 개별 프로젝트에서 관리해야 합니다. 부분. 그렇지 않으면 루트 POM 버전 번호를 제대로 유지하기가 어렵습니다.
Java의 가장 좋은 점 중 하나는 모든 작업을 수행하는 엄청난 양의 타사 라이브러리입니다. 기본적으로 모든 API 또는 툴킷에는 Java SDK가 있으며 Maven을 사용하여 쉽게 가져올 수 있습니다.
그리고 이러한 Java 라이브러리 자체는 다른 라이브러리의 특정 버전에 의존합니다. 충분한 라이브러리를 가져오면 다음과 같은 버전 충돌이 발생합니다.
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
어떤 버전이 프로젝트에 포함되나요?
Maven 종속성 수렴 플러그인을 사용하면 종속성이 동일한 버전을 사용하지 않으면 빌드에 오류가 발생합니다. 그런 다음 충돌을 해결하기 위한 두 가지 옵션이 있습니다.
선택할 항목은 상황에 따라 다릅니다. 한 프로젝트의 버전을 추적하려면 제외하는 것이 좋습니다. 반면에 명시적으로 설명하고 싶다면 버전을 선택할 수 있습니다. 단, 다른 종속성을 업데이트할 때 버전도 업데이트해야 합니다.
분명히 SNAPSHOT 버전을 지속적으로 구축하고 git 태그를 기반으로 태그를 빌드하는 일종의 지속적인 통합 서버가 필요합니다.
Jenkins와 Travis-CI는 자연스러운 선택입니다.
코드 적용 범위는 유용하며 Cobertura는 우수한 Maven 플러그인 및 CI 지원을 제공합니다. Java용 다른 코드 적용 도구가 있지만 저는 Cobertura를 사용했습니다.
자신이 만든 JAR, WAR 및 EAR을 저장할 장소가 필요하므로 저장소가 필요합니다.
일반적인 선택은 Artifactory와 Nexus입니다. 둘 다 작동하며 각각의 장단점이 있습니다.
자체 Artifactory/Nexus 설치가 있어야 하며 여기에 종속성을 미러링해야 합니다. 이렇게 하면 일부 업스트림 Maven 저장소가 다운되어 빌드가 중단되는 것을 막을 수 있습니다.
이제 코드를 컴파일하고 저장소를 설정했으며 개발 환경에서 코드를 가져와 최종적으로 프로덕션에 푸시해야 합니다. 여기서 인색하지 마십시오. 자동화하면 오랫동안 이익을 얻을 수 있기 때문입니다.
Chef, Puppet 및 Ansible이 일반적인 선택입니다. 나는 Squadron이라는 대안을 작성했습니다. 물론 대안보다 올바른 방법을 찾는 것이 더 쉽기 때문에 확인해야 한다고 생각합니다.
어떤 도구를 선택하든 배포를 자동화하는 것을 잊지 마십시오.
아마도 Java의 가장 큰 특징은 방대한 양의 라이브러리가 있다는 것입니다. 이것은 가장 큰 규모의 사람들에게 적용될 수 있는 작은 도서관 모음입니다.
한때 놀라운 발전을 이루었던 Java의 표준 라이브러리는 이제 몇 가지 주요 기능이 누락된 것처럼 보입니다.
Apache Commons 프로젝트에는 유용한 라이브러리가 많이 있습니다.
Commons Codec 에는 Base64 및 16진수 문자열에 대한 유용한 인코딩/디코딩 방법이 많이 있습니다. 다시 작성하는데 시간을 낭비하지 마세요.
Commons Lang은 문자열 조작 및 생성, 문자 세트 및 다양한 기타 유틸리티 방법을 위한 라이브러리입니다.
Commons IO 에는 여러분이 원할 수 있는 모든 파일 관련 방법이 있습니다. FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines 등이 있습니다.
Guava는 Google의 탁월한 Java에 누락된 라이브러리입니다. 이 도서관에 대해 제가 좋아하는 모든 것을 추출하는 것은 거의 어렵지만 시도해 보겠습니다.
캐시 는 네트워크 액세스, 디스크 액세스, 메모 기능 등을 캐시하는 데 사용할 수 있는 메모리 내 캐시를 얻는 간단한 방법입니다. Guava에게 캐시 구축 방법을 알려주는 CacheBuilder를 구현하기만 하면 모든 준비가 완료됩니다!
불변 컬렉션. ImmutableMap, ImmutableList 또는 ImmutableSortedMultiSet(원하는 경우) 등 여러 가지가 있습니다.
나는 또한 Guava 방식으로 변경 가능한 컬렉션을 작성하는 것을 좋아합니다.
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
목록, 지도, 집합 등에 대한 정적 클래스가 있습니다. 더 깨끗하고 읽기 쉽습니다.
Java 6 또는 7을 사용하는 경우 필터 및 변환과 같은 메서드가 있는 Collections2 클래스를 사용할 수 있습니다. 이를 통해 Java 8의 스트림 지원 없이도 유창한 코드를 작성할 수 있습니다.
Guava에는 구분 기호의 문자열을 결합하는 Joiner 와 인터럽트를 무시하여 인터럽트를 처리하는 클래스와 같은 간단한 기능도 있습니다.
Google의 Gson 라이브러리는 간단하고 빠른 JSON 구문 분석 라이브러리입니다. 다음과 같이 작동합니다.
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
정말 쉽고 즐겁게 작업할 수 있습니다. Gson 사용자 가이드에는 더 많은 예제가 있습니다.
Java에서 제가 계속 겪고 있는 불만 사항 중 하나는 표준 라이브러리에 튜플이 내장되어 있지 않다는 것입니다. 다행히도 Java 튜플 프로젝트가 이 문제를 해결했습니다.
사용하기 쉽고 훌륭하게 작동합니다.
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang은 Java 8의 일부였어야 했던 누락된 기능을 추가하도록 설계된 기능적 라이브러리입니다. 이러한 기능 중 일부는 다음과 같습니다.
원래 Java 컬렉션에 의존하는 여러 Java 라이브러리가 있습니다. 이는 객체 지향에 중점을 두고 생성되고 변경 가능하도록 설계된 클래스와 호환되도록 제한됩니다. Java용 Javaslang 컬렉션은 Haskell, Clojure 및 Scala에서 영감을 받아 완전히 새로운 버전입니다. 기능에 중점을 두고 제작되었으며 불변의 디자인을 따릅니다.
다음과 같은 코드는 자동으로 스레드로부터 안전하고 try-catch가 없습니다.
// Success/Failure containing the result/exception
public static Try < User > getUser ( int userId ) {
return Try . of (() -> DB . findUser ( userId ))
. recover ( x -> Match . of ( x )
. whenType ( RemoteException . class ). then ( e -> ...)
. whenType ( SQLException . class ). then ( e -> ...));
}
// Thread-safe, reusable collections
public static List < String > sayByeBye () {
return List . of ( "bye, " bye ", "collect" , "mania" )
. map ( String :: toUpperCase )
. intersperse ( " " );
}
Joda-Time은 제가 사용해 본 최고의 시간 라이브러리입니다. 간단하고 간단하며 테스트하기 쉽습니다. 또 무엇을 요청할 수 있나요?
아직 Java 8을 사용하지 않는 경우에만 이 기능이 필요합니다. Java 8에는 좋지 않은 새로운 시간 라이브러리가 있기 때문입니다.
Lombok은 흥미로운 도서관입니다. 주석을 통해 Java가 심하게 겪고 있는 상용구를 줄일 수 있습니다.
클래스 변수에 대한 setter 및 getter를 원하십니까? 단순한:
public class Foo {
@ Getter @ Setter private int var ;
}
이제 다음을 수행할 수 있습니다.
final Foo foo = new Foo ();
foo . setVar ( 5 );
그리고 훨씬 더 많은 것이 있습니다. 아직 프로덕션 환경에서 Lombok을 사용해 본 적은 없지만, 기대가 됩니다.
좋은 대안 : Jersey 또는 Spark
Java에서 RESTful 웹 서비스를 수행하기 위한 두 가지 주요 캠프는 JAX-RS와 기타 모든 것입니다.
JAX-RS는 전통적인 방식입니다. Jersey와 같은 것을 사용하여 웹 서비스를 형성하기 위해 주석을 인터페이스 및 구현과 결합합니다. 이것의 좋은 점은 인터페이스 클래스만으로 클라이언트를 쉽게 만들 수 있다는 것입니다.
Play 프레임워크는 JVM의 웹 서비스에 대한 근본적으로 다른 해석입니다. 경로 파일이 있고 해당 경로에서 참조되는 클래스를 작성합니다. 실제로는 전체 MVC 프레임워크이지만 REST 웹 서비스에만 쉽게 사용할 수 있습니다.
Java와 Scala 모두에서 사용할 수 있습니다. Scala 우선이라는 점에서 약간의 어려움이 있지만 Java에서 사용하는 것은 여전히 좋습니다.
Python의 Flask와 같은 마이크로 프레임워크에 익숙하다면 Spark가 매우 익숙할 것입니다. 특히 Java 8에서 잘 작동합니다.
Java 로깅 솔루션이 많이 있습니다. 제가 가장 좋아하는 것은 SLF4J입니다. 왜냐하면 플러그형이 매우 뛰어나고 다양한 로깅 프레임워크의 로그를 동시에 결합할 수 있기 때문입니다. java.util.logging, JCL 및 log4j를 사용하는 이상한 프로젝트가 있습니까? SLF4J는 당신을 위한 것입니다.
두 페이지로 구성된 설명서는 시작하는 데 필요한 거의 모든 것입니다.
나는 SQL을 좋아하기 때문에 무거운 ORM 프레임워크를 싫어합니다. 그래서 JDBC 템플릿을 많이 작성했는데 유지 관리가 좀 힘들었어요. jOOQ는 훨씬 더 나은 솔루션입니다.
이를 사용하면 유형이 안전한 방식으로 Java에서 SQL을 작성할 수 있습니다.
// Typesafely execute the SQL statement directly with jOOQ
Result < Record3 < String , String , String >> result =
create . select ( BOOK . TITLE , AUTHOR . FIRST_NAME , AUTHOR . LAST_NAME )
. from ( BOOK )
. join ( AUTHOR )
. on ( BOOK . AUTHOR_ID . equal ( AUTHOR . ID ))
. where ( BOOK . PUBLISHED_IN . equal ( 1948 ))
. fetch ();
이 패턴과 DAO 패턴을 사용하면 데이터베이스 액세스가 쉬워집니다.
테스트는 소프트웨어에 매우 중요합니다. 이 패키지를 사용하면 작업이 더 쉬워집니다.
좋은 대안 : TestNG.
jUnit은 소개가 필요하지 않습니다. Java의 단위 테스트를 위한 표준 도구입니다.
하지만 아마도 jUnit을 최대한 활용하지 못할 수도 있습니다. jUnit은 매개변수화된 테스트, 너무 많은 상용구를 작성하지 않도록 하는 규칙, 특정 코드를 무작위로 테스트하는 이론 및 가정을 지원합니다.
종속성 주입을 수행했다면 이것이 성과를 거두는 곳입니다. 즉, 부작용이 있는 코드를 조롱하고(예: REST 서버와 통신) 이를 호출하는 코드의 동작을 계속 주장하는 것입니다.
jMock은 Java용 표준 모의 도구입니다. 다음과 같습니다.
public class FooWidgetTest {
private Mockery context = new Mockery ();
@ Test
public void basicTest () {
final FooWidgetDependency dep = context . mock ( FooWidgetDependency . class );
context . checking ( new Expectations () {{
oneOf ( dep ). call ( with ( any ( String . class )));
atLeast ( 0 ). of ( dep ). optionalCall ();
}});
final FooWidget foo = new FooWidget ( dep );
Assert . assertTrue ( foo . doThing ());
context . assertIsSatisfied ();
}
}
이는 jMock을 통해 FooWidgetDependency를 설정한 다음 기대치를 추가합니다. 우리는 dep 의 call 메소드가 일부 String과 함께 한 번 호출되고 dep 의 optionCall 메소드가 0회 이상 호출될 것으로 예상합니다.
동일한 종속성을 계속해서 설정해야 한다면 이를 테스트 픽스처에 넣고 @After 픽스처에 AssertIsSatisfied를 넣어야 할 것입니다.
jUnit으로 이런 작업을 해본 적이 있나요?
final List < String > result = some . testMethod ();
assertEquals ( 4 , result . size ());
assertTrue ( result . contains ( "some result" ));
assertTrue ( result . contains ( "some other result" ));
assertFalse ( result . contains ( "shouldn't be here" ));
이것은 단지 짜증나는 상용구입니다. AssertJ가 이 문제를 해결합니다. 동일한 코드를 다음과 같이 변환할 수 있습니다.
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
이 유창한 인터페이스를 통해 테스트를 더 쉽게 읽을 수 있습니다. 무엇을 더 원할 수 있나요?
좋은 대안 : Eclipse와 Netbeans
최고의 Java IDE는 IntelliJ IDEA입니다. 여기에는 수많은 멋진 기능이 있으며 실제로 Java의 장황함을 표현 가능하게 만드는 주요 요소입니다. 자동완성은 훌륭하고 검사는 최고 수준이며 리팩토링 도구는 정말 유용합니다.
무료 커뮤니티 에디션이면 충분하지만 Ultimate 에디션에는 데이터베이스 도구, Spring Framework 지원, Chronon과 같은 훌륭한 기능이 많이 있습니다.
GDB 7에서 제가 가장 좋아하는 기능 중 하나는 디버깅할 때 시간을 거슬러 올라갈 수 있는 기능이었습니다. 이는 Ultimate 에디션을 구입하면 Chronon IntelliJ 플러그인을 사용하여 가능합니다.
변수 기록, 뒤로 이동, 메소드 기록 등을 얻을 수 있습니다. 처음 사용하는 것이 조금 이상하지만 실제로 복잡한 버그, Heisenbugs 등을 디버깅하는 데 도움이 될 수 있습니다.
좋은 대안 : DCEVM
지속적인 통합은 종종 SaaS(Software-as-a-Service) 제품의 목표입니다. 코드 변경 사항을 실시간으로 확인하기 위해 빌드가 완료될 때까지 기다릴 필요조차 없다면 어떻게 될까요?
그것이 바로 JRebel이 하는 일입니다. 서버를 JRebel 클라이언트에 연결하면 서버의 변경 사항을 즉시 확인할 수 있습니다. 신속하게 실험하고 싶을 때 시간이 크게 절약됩니다.
Java의 유형 시스템은 매우 약합니다. 문자열과 실제로 정규식인 문자열을 구별하지 않으며 오염 검사도 수행하지 않습니다. 그러나 Checker Framework는 이 작업 외에도 그 이상을 수행합니다.
@Nullable 과 같은 주석을 사용하여 유형을 확인합니다. 정적 분석을 더욱 강력하게 수행하기 위해 자신만의 주석을 정의할 수도 있습니다.
모범 사례를 따를 때에도 최고의 개발자라도 실수를 할 수 있습니다. 코드의 문제를 감지하기 위해 Java 코드의 유효성을 검사하는 데 사용할 수 있는 다양한 도구가 있습니다. 다음은 가장 널리 사용되는 도구 중 일부입니다. 이들 중 다수는 Eclipse 또는 IntelliJ와 같은 널리 사용되는 IDE와 통합되어 코드에서 실수를 더 빨리 발견할 수 있습니다.
개발 중에 이러한 도구를 사용할 뿐만 아니라 빌드 단계에서도 실행하는 것이 좋은 경우가 많습니다. Maven 또는 Gradle과 같은 빌드 도구 및 지속적인 통합 도구에 연결할 수 있습니다.
Java에서도 메모리 누수가 발생합니다. 다행히도 이를 위한 도구가 있습니다. 이 문제를 해결하기 위해 제가 사용한 최고의 도구는 Eclipse 메모리 분석기입니다. 힙 덤프가 필요하며 문제를 찾을 수 있습니다.
JVM 프로세스에 대한 힙 덤프를 얻는 방법에는 몇 가지가 있지만 저는 jmap을 사용합니다.
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created
그런 다음 메모리 분석기로 heapdump.hprof 파일을 열고 무슨 일이 일어나고 있는지 빠르게 확인할 수 있습니다.
Java 마스터가 되는 데 도움이 되는 리소스입니다.