Enum
Java의 Enum은 C, C++과 다르게 클래스로 인식한다.
public enum Category{
SNACK("과자",Arrays.asList("플랑","빈츠")),
DISPOSABLE_PRODUCTS("일회용품",Arrays.asList("나무젓가락","종이컵")),
DAILY_NECESSITY("생필품",Arrays.asList("물티슈","휴지")),
EMPTY("없음", Collection.EMPTY_LIST);
private List<String> cateList;
public static Category findbyCategoryCode(String code){
return Arrays.stream(Category.values())
.filter(Category -> Category.hasCode(code))
.findAny()
.orElse(EMPTY)
}
public boolean hasCode(String code){
return cateList.stream()
.anyMatch(category -> category.equals(code));
}
}
위와 같이 enum 을 클래스처럼 정의할 수 있으므로 내부에 메소드 또한 만들 수 있다.
Enum 메소드
| Static method | 설명 |
|---|---|
| valueOf(String arg) | String 값을 enum에서 가져온다. 값이 없으면 예외 발생, 내부적으로 자신의 클래스에서 찾아온다 |
| valueOf(Class<> class, Stirng arg | 클래스에서 String값을 찾아 enum에 가져온다. |
| values() | enum의 요소들을 순서대로 가져온다. |
| Non Static method | 설명 |
|---|---|
| ordinal() | 해당 상수가 열거 타입의 몇 번째 위치인지 반환한다. |
| compareTo(E o) | enum과 지정된 객체의 순서를 비교. 지정된 객체보다 작은 경우 음의 정수, 동일하면 0, 크면 양의 정수를 리턴한다. |
| equals(Object other) | 지정된 객체가 enum 정수와 같은경우, true를 리턴한다. |
| name() | 호출된 값의 이름을 String으로 리턴한다. |
EnumSet
Enum 값만 포함할 수 있고, 모든 값은 동일한 enum에 속해야 된다.
null 추가를 허용하지 않는다.
thread로부터 안전하지 않다. 필요한 경우 외부에서 동기화를 해야된다.
hashSet보다 몹시 빠르다.
값을 예측 가능한 순서로 저장하며 각각의 계산에 단 하나의 비트만 검사하면 된다.
비트 벡터의 특성으로 인해 메모리를 덜 사용한다.
Annotation
위키백과에서의 정의로는
자바 소스 코드에 추가하여 사용할 수 있는 메타데이터의 일종이다. 보통 @ 기호를 앞에 붙여서 사용한다. JDK 1.5 버전 이상에서 사용 가능하다. 자바 애너테이션은 클래스 파일에 임베디드되어 컴파일러에 의해 생성된 후 자바 가상머신에 포함되어 작동한다.
쉽게 생각하자면 Java 코드와 그 코드 관련 설정 파일을 하나로 합쳐서 관리하는 방법이다.
Annotation 종류
표준 어노테이션 : 자바가 기본적으로 제공해주는 어노테이션
메타 어노테이션 : 어노테이션을 위한 어노테이션
사용자 정의 어노테이션 : 사용자가 직접 정의하는 어노테이션
메타 어노테이션
retention : 어노테이션이 유지되는 기간을 지정하는데 사용한다.
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter{
//... 관련 내용 코드
}
RetentionPolicy.SOURCE는 .java 소스 파일까지는 남아있고 컴파일 시 클래스 파일이 되면 사라진다.
target : 적용 대상을 지정하는데 사용한다.
위 코드에서는 Field, class, interface, enum 타입에 어노테이션을 사용할 수 있다는 것을 의미한다.
documented : javadocs 에 어노테이션의 사용을 문서화해준다.
Annotation Processor
정의 : 컴파일 단계에서 Annotation에 정의된 일렬의 프로세스를 동작하게 하는 것을 의미한다.
예시를 들면 Lombok 어노테이션이 있다.
@Getter
@Setter
public class A{
private int a;
private int b;
}
위 코드는 a와 b에대한 get, set 메소드가 없어도 사용할 수 있게 만들어 주는 어노테이션이다.
그럼 실제 Getter와 Setter는 어떻게 정의되어 있을까?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Hello{
}
@SupportedAnnotationTypes("me.maru.anno.Hello") @SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class GetterProcessor extends AbstractProcessor{
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironmentroundEnv) {
//애노테이션이 붙은 Element를 가져옴
Set<? extends Element> elements =roundEnv.getElementsAnnotatedWith(HappyData.class);
for(Element element : elements) {
Name elementName = element.getSimpleName();
if (element.getKind() != ElementKind.CLASS) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Annotation Error >> not supported type : " + elementName);
}else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Annotation Processing >>> " + elementName);
//멤버 변수, setter, getter 를 가진 클래스 생성
createClassWithSetterAndGetter(element);
}
}
return true
}
private void createClassWithSetterAndGetter(Element element) {
TypeElement typeElement = (TypeElement) element;
ClassName className = ClassName.get(typeElement);
//멤버 변수, setter, getter 를 가진 클래스 정의
TypeSpec classImpl = getClassSpecWithSetterAndGetter(element, className);
Filer filer = processingEnv.getFiler();
try {
JavaFile.builder(className.packageName(), classImpl)
.build()
.writeTo(filer);
} catch(IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error >> " + e);
private TypeSpec getClassSpecWithSetterAndGetter(Element element, ClassName className) {
//해당 클래스의 Element 들
List<? extends Element> fields = element.getEnclosedElements();
//새로운 클래스의 멤버변수들
List<FieldSpec> fieldList = new ArrayList<>();
//새로운 클래스의 메서드들
List<MethodSpec> methodList = new ArrayList<>();
for(Element field : fields) {
//멤버변수가 아닌 경우는 pass
if (field.getKind() != ElementKind.FIELD) continue;
String fieldName = field.getSimpleName().toString();
TypeName fieldTypeName = TypeName.get(field.asType());
//새로운 클래스에 본 클래스의 멤버변수 추가
fieldList.add(getFieldSpec(fieldTypeName, fieldName));
//새로운 클래스에 getter 추가
methodList.add(getGetterSpec(fieldTypeName, fieldName));
//새로운 클래스에 setter 추가
methodList.add(getSetterSpec(fieldTypeName, fieldName));
}
//새로 생성되는 클래스 명은 본 클래스 + Data
return TypeSpec.classBuilder(className.simpleName() + "Data")
.addModifiers(Modifier.PUBLIC)
.addFields(fieldList)
.addMethods(methodList)
.build();
private MethodSpec getSetterSpec(TypeName fieldTypeName, String fieldName) {
//setter 명
String setterName = String.format("set%s", StringUtils.capitalize(fieldName));
//setter body
String setterStatement = String.format("this.%s = %s", fieldName, fieldName);
return MethodSpec.methodBuilder(setterName)
.addModifiers(Modifier.PUBLIC)
.addParameter(fieldTypeName, fieldName)
.addStatement(setterStatement)
.build();
}
private MethodSpec getGetterSpec(TypeName fieldTypeName, String fieldName) {
//getter 명
String getterName = String.format("get%s", StringUtils.capitalize(fieldName));
//setter body
String getterStatement = String.format("return this.%s", fieldName);
return MethodSpec.methodBuilder(getterName)
.addModifiers(Modifier.PUBLIC)
.returns(fieldTypeName)
.addStatement(getterStatement)
.build();
}
private FieldSpec getFieldSpec(TypeName fieldTypeName, String fieldName) {
return FieldSpec.builder(fieldTypeName, fieldName)
.addModifiers(Modifier.PRIVATE)
.build();
위 코드는 Hello 어노테이션을 직접 구현한 부분이다. 이 어노테이션은 Lombok에 있는 Getter와 Setter를 구현한 것으로 프로세서를 직접 구현할 수 있다는 것을 알 수 있다.
'Java' 카테고리의 다른 글
| Java Study 7-1주차 (0) | 2023.11.18 |
|---|---|
| Java Study 6-2주차 (0) | 2023.11.11 |
| Java Study 5-2주차 (0) | 2023.11.05 |
| Java Study 5-1주차 (0) | 2023.11.05 |
| Java Study 4주차 (1) | 2023.10.29 |