Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

243
Visualizações
Code reuse: returning lists of enum fields with common getter methods

I have two enums:

Main Menu Options

public enum MainMenuOptions {
    
    EXIT("Exit"),
    VIEW_RESERVATIONS("View Reservations By Host"),
    CREATE_RESERVATION("Create A Reservation"),
    EDIT_RESERVATION("Edit A Reservation"),
    CANCEL_RESERVATION("Cancel A Reservation");
    
    private final String message;
    
    MainMenuOptions(String message) {
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
    
    public static List<String> asListString() {
        return Arrays.stream(MainMenuOptions.values())
                .map(MainMenuOptions::getMessage)
                .collect(Collectors.toList());
    }
}

Host Selection Method Options

public enum HostSelectionMethodOptions {
    
    FIND_ALL("Find all"),
    FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
    FIND_BY_CITY_STATE("Find by city & state");
    
    String message;
    
    HostSelectionMethod(String message) {
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
    
    public static List<String> asListString() {
        return Arrays.stream(HostSelectionMethod.values())
                .map(HostSelectionMethod::getMessage)
                .collect(Collectors.toList());
    }
}

Both enums share the same field

private final String message;

The same getter

public String getMessage() {
    return message;
}

And the same asListString() method

public static List<String> asListString() {
    return Arrays.stream(MainMenuOptions.values())
            .map(MainMenuOptions::getMessage)
            .collect(Collectors.toList());
}

How can I DRY out these enums?

I expect to have more enums with the same fields and methods, and it seems silly to write out the same thing over and over again for each one.

  • I tried making both of the enums extend a superclass, but enums cannot have extends clauses
  • I can create an interface that specifies the contract for the asListString() method, but that doesn't allow me to actually reuse any code.

The flavor I was hoping the code could have is something like this:

public class Utils {
    
    public static List<String> enumAsListString(Enum e) {
        return e.values().stream.map(e::getMessage).collect(Collectors.toList());
    }
}
over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

This is probably one of the cases where you need to pick one between being DRY and using enums.

Enums don't go very far as far as code reuse is concerned, in Java at least; and the main reason for this is that primary benefits of using enums are reaped in static code - I mean static as in "not dynamic"/"runtime", rather than static :). Although you can "reduce" code duplication, you can hardly do much of that without introducing dependency (yes, that applies to adding a common API/interface, extracting the implementation of asListString to a utility class). And that's still an undesirable trade-off.

Furthermore, if you must use an enum (for such reasons as built-in support for serialization, database mapping, JSON binding, or, well, because it's data enumeration, etc.), you have no choice but to duplicate method declarations to an extent, even if you can share the implementation: static methods just can't be inherited, and interface methods (of which getMessage would be one) shall need an implementation everywhere. I mean this way of being "DRY" will have many ways of being inelegant.

If I were you, I would simply make this data completely dynamic

final class MenuOption {
    private final String category; //MAIN_MENU, HOT_SELECTION
    private final String message; //Exit, View Reservation By Host, etc.
    public static MenuOption of(String key, String message) {
        return new MenuOption(key, message);
    }
}

This is very scalable, although it introduces the need to validate data where enums would statically prevent bad options, and possibly custom code where an enum would offer built-in support.

It can be improved with a "category" enum, which gives static access to menu lists, and a single place for asListString():

enum MenuCategory {
    MAIN_MENU(
        MenuOption.of("Exit"), 
        MenuOption.of("View Reservations By Host")
    ),
    HOT_SELECTION(
        MenuOption.of("Find All")
    );
    
    private final List<MenuOption> menuOptions;
    
    MenuCategory(MenuOption... options) {
        this.menuOptions = List.of(options); //unmodifiable
    }
    
    public List<String>asListString() {
        return this.menuOptions.stream()
                   .map(MenuOption::getMessage)
                   .collect(Collectors.toList());
    }
}

It should be clear that you can replace class MenuOption with a bunch of enums implementing a common interface, which should change little to nothing in MenuCategory. I wouldn't do that, but it's an option.

over 4 years ago · Santiago Trujillo Relatório

0

You can DRY it a little.

Utils.java

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public interface Utils<T>
{

   public String getMessage();

   public static <T extends Utils<T>> List<String> asListString(Class<T> clazz)
   {
   
      return Arrays.stream(clazz.getEnumConstants())
                .map(T::getMessage)
                .collect(Collectors.toList());
   
   }
   
}

HostSelectionMethodOptions.java

public enum HostSelectionMethodOptions implements Utils<HostSelectionMethodOptions> {
   
   FIND_ALL("Find all"),
   FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
   FIND_BY_CITY_STATE("Find by city & state");
   
   private final String message;
   
   HostSelectionMethodOptions(String message) {
      this.message = message;
   }
   
   public String getMessage() {
      return message;
   }
   
}

Then just do this - Utils.asListString(HostSelectionMethodOptions.class);

over 4 years ago · Santiago Trujillo Relatório

0

I basically had the same idea as davidalayachew.

An enum can implement an interface. So if you create a common asListString which accepts an enum type, you could get the desired result.

First, create an Options interface and let both enums implement it:

interface Options {
    String getMessage();
}
enum HostSelectionMethodOptions implements Options { ... }
enum MainMenuOptions implements Options { ... }

Now create a method like this:

public static <T extends Enum<T> & Options> List<String> asListString(Class<T> type) {
    return Arrays.stream(type.getEnumConstants())
        .map(T::getMessage)
        .collect(Collectors.toList());
}

The method declares a type argument: <T extends Enum<T> & Options>. Here, T is an intersection type, so it extends both Enum and the Options interface. You can call it like this:

asListString(MainMenuOptions.class);
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda