Enum-Всемогутній

Вступна
Дуже часто, ми використовуємо інструменти строго за призначенням, забороняючи собі робити крок вліво або вправо. Але що якщо ми трохи 'забудемся'? Що, якщо ми подивимося на звичні нам речі під іншим кутом? У цій статті зібрані підходи використання перерахувань та проведено невеличкий експеримент над ними. Сарказм, гумор і трохи филосовских питань. Кому цікаво, ласкаво просимо під кат.

Застереження
В цій статті ви не знайдете для себе нових технічних знань, одкровень, а якщо Ви жадаєте їх — то сміливо переходьте до наступної статті. Тим не менш, тут є чому дивуватися і є над чим подумати. Технічний гумор і филосовские думки між рядків.

Не розказана історія...
Одного разу потрапляє розробник у місце, де вирішують долю. Час, перед ним з'являється образ і питає:
— Хто ти?
— Я, розробник, звати Іван, — а про себе: устряв.
Голос знову:
— Хочеш туди?. Погляд на двері, за якої рай.
— Ага, — несміливо Іван.
— Що повідаєш мені?, — запитує Голос.
Трохи подумавши, Іван починає говорити:
— Є в java Enum-Всемогутній.
— Як так, Всемогутній? — перебиває Голос з обуренням.— Це тільки перерахування!

public enum JavaLanguage {
JAVA("Forever"),
SCALA("Next generation") {},
KOTLIN("Future") {};
private final String claim;
JavaLanguage(String claim) {
this.claim = claim;
}
public String getClaim() {
return claim;
}
}

— Ага, — відповідає розроблення дизайн, Але не тільки.
— Доведи!
— Enum як цвяхи, утильним могьоть.

public enum LanguageUtils {
;
/** java-doc */
LanguageUtils() {
throw new IllegalStateException("Це не перерахування");
}
/** java-doc */
public static String[] getKeyWords(String languageName) {
if (languageName != null) {
// трохи логіки тут
return loadFromResource(languageName + "/keywords.dat");
}
throw new IllegalStateException("Необхідно вказати мову");
}
/** java-doc */
private static synchronized String[] loadFromResource(String resourceName) {
String[] items = null;
// Код завантаження тут
return items;
}
/** Багато статичних методів тут */
}

— У так чудеса, але… Спадкоємця у нього немає!
— А це як подивитися. А кого вважати Спадкоємцем? Scala? Kotlin?
— Давай приклад, не чекаючи поки розроблення дизайн завершить своє питання

// JavaLanguage.java файл
public static void main(String[] args) {
// it's true
if (JAVA.getClass() == SCALA.getClass().getSuperclass()) {
System.out.println("Спадкоємець то є!");
}
// it's true
if (JAVA.getClass() == KOTLIN.getClass().getSuperclass()) {
System.out.println("Та не один!");
}
}

— Авжеж, цікаві Ви хлопці, прогеры — вже посміхаючись, говорить Голос,— Але малова-то буде
Почухавши ріпу, Іван продовжив:
— Enum-то у нас фабрика!
— Не було вже.
Довелося, Івану останній козир дістати:
— Enum-Одинак, точно!
Обери своє
Ти за Java?
public enum Highlander {
JAVA;
Highlander() {
if (ordinal() != 0) {
throw new IllegalStateException("В живих повинен залишитися тільки один");
}
init();
}
private void init() {
// код тут!
}
/** java-doc */
public String getOwner(String index) {
// логіка тут
return "Джеймс Гослінг, Sun Microsystems";
}
}

Ти за Scala?
public enum Highlander {
SCALA {};
Highlander() {
if (ordinal() != 0) {
throw new IllegalStateException("В живих повинен залишитися тільки один");
}
init();
}
private void init() {
// код тут!
}
/** java-doc */
public String getOwner(String index) {
// логіка тут
return "Мартін Одерски, Федеральна політехнічна школа Лозанни";
}
}

Ти за Kotlin?
public enum Highlander {
KOTLIN {};
Highlander() {
if (ordinal() != 0) {
throw new IllegalStateException("В живих повинен залишитися тільки один");
}
init();
}
private void init() {
// код тут!
}
/** java-doc */
public String getOwner(String index) {
// логіка тут
return "Андрій Бреслава, JetBrains";
}
}

— Джошуа Блох каже*, що це найкраща реалізація Сінглтона.
— Ну а ти?
— А що я? Це, це — це сінглтон-фабрика, для зберігання одного єдиного елемента, нути бити...

Highlander.valueOf("JAVA");
Це точка для доступу до масиву для зберігання одного єдиного елемента, нути бити...
Highlander.values()[0];
Це спадкоємець класу ..., — хотів було продовжити Іван, але був приємно здивований:
— Проходь...

Трохи висновків
Разом виходить, що enum можна наділити такими якостями і властивостями, в залежності від точки огляду:
  • Перерахування і дані
  • Каркас для утилитного класу
  • Каркас для сінглтона класу + антипатерн додається
  • Каркас для фабрики


Експеримент
Я вирішив зрозуміти, скільки можна максимально згенерувати елементів перерахувань. Мій власний відповідь і реальність настільки розійшлися, що я засумнівався у своїх знаннях. Перш ніж Ви подивіться нижче спробуйте дати відповідь самостійно. Спростимо, скажіть хоча б порядок? Ось код, який я використовував для генерації класу перерахувань (на швидку руку):

Код-генерації enum?
package com.enums;

import java.io.*;

public class EnumGeneratorShort implements Closeable {
private BufferedWriter writer;
public EnumGeneratorShort(File пропустити, результати) throws IOException {
writer = new BufferedWriter(new FileWriter(пропустити, результати));
}
void append(String line) throws IOException {
writer.append(line);
}
void appendLine(String line) throws IOException {
writer.append(line).append("\n");
}
@Override
public void close() throws IOException {
if (writer != null) {
writer.close();
}
}
/** Скільки згенерувати enum*/
private static final int ENUM_COUNT = XXXX; // де XXXX - розмір
private static final char[] ALPHABET = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', z'};
public static void main(String[] args) throws IOException {
System.out.println("Start generation");
File пропустити, результати = new File("src/main/java/com/enums/BigEnumShort.java");
try (EnumGeneratorShort enumGen = new EnumGeneratorShort(пропустити, результати)) {
enumGen.appendLine("package com.enums;");
enumGen.appendLine("");
enumGen.appendLine("public enum BigEnumShort {");
enumGen.append("A");
int index = 1;
for (; index < ENUM_COUNT; index++) {
enumGen.appendLine(",");
String name = getName(index, "");
if ("if".equals(name) || "do".equals(name)) {
name = getName (index++, "");
}
enumGen.append(name);
}
enumGen.appendLine(";");
enumGen.appendLine("");
enumGen.appendLine(" public static void main(String[] args) {");
enumGen.appendLine(" System.out.println(\"Find enum \" + BigEnumShort.valueOf(\"B\"));");
enumGen.appendLine(" }");
enumGen.appendLine("}");
System.out.println("End generation. Total " + index);
}
}
public static String getName(int index, String before) {
if (index < ALPHABET.length) {
return before + ALPHABET[index];
}
int tail = index / ALPHABET.length;
int current = index % ALPHABET.length;
return getName(tail, before + ALPHABET[current]);
}
}

Ви вже припустили? Так от, на семерочке мені вдалося згенерувати всього 2746 елементів перерахувань. А далі ось це:

Ошибка_3Total 5000
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project bigenum: Compilation failure
[ERROR] /home/XXX/temp/BigEnum/bigenum/src/main/java/com/enums/BigEnumShort.java:[4,1] code too large

Але, так як я розкотив губу в 4 поверхи, спочатку я отримав таку помилку:
Ошибка_1Total 134217727
Compiling 1 source file to /home/XXX/temp/BigEnum/bigenum/target/classes
An exception has occurred in the compiler (1.7.0_51). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.IllegalArgumentException

А потім, трохи підвернувши її, таку:
Ошибка_2Total 8388607
ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project bigenum: Compilation failure: Compilation failure:
[ERROR] /home/XXX/temp/BigEnum/bigenum/src/main/java/com/enums/BigEnumShort.java:[4,1] code too large
[ERROR] /home/XXX/temp/BigEnum/bigenum/src/main/java/com/enums/BigEnumShort.java:[3,8] too many constants

Ще мені було цікаво, як таке перерахування зможуть переварити відомі декомпиляторы. Разом за суб'єктивною оцінкою очікування:
Місце Декомпілятор Результат
1 fernflower.jar OK
2 jad OK
3 procyon Дочекався
4 cfr_0_115.jar Не дочекався


Дякую вам за увагу.

Джерела і натхненники
Effective Java, 2nd Edition, by Joshua Bloch*
Вікіпедія
Правильний Singleton в Java
Коментар apanasevich
Коментар Sirikid
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.