Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

240
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!