Featured image of post 【Java】Enum

【Java】Enum

Java enums are a special type of class used to define collections of constants. They provide a way to represent a fixed set of values, which can be useful for categorizing data and ensuring type safety.

Key Points

  • Implicitly final and static: Enum constants are implicitly public, static, and final.
  • values() method: Every enum has a static values() method that returns an array of all enum constants.
  • valueOf(String) method: This static method returns the enum constant with the specified name.
  • The name() method returns the name of the enum constant as declared in its enum declaration. It’s an instance method available on all enum constants.
  • valueOf(String) and name() provide a way to convert between the Enum and String.
  • ordinal() method: Returns the position of the enum constant (zero-based).
  • Constructors, Fields, and Methods: Enums can have constructors, fields, and methods, allowing you to associate data and behavior with each constant.
  • Implementing Interfaces: Enums can implement interfaces, providing a way to define behavior for each constant.
  • EnumSet and EnumMap: These are specialized Set and Map implementations for use with enum types, offering better performance than their general-purpose counterparts.
  • Constant-specific method implementation: You can override methods for specific enum constants, allowing for different behavior per constant.
  • Abstract methods in enums: You can define abstract methods in an enum, forcing each constant to provide its own implementation.

example

// Basic enum definition
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

// Enum with constructor, fields, and methods
public enum Planet {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6);

    private final double mass;   // in kilograms
    private final double radius; // in meters

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    public double getMass() {
        return mass;
    }

    public double getRadius() {
        return radius;
    }

    // Enum constant-specific method implementation
    public double surfaceGravity() {
        return 6.67300E-11 * mass / (radius * radius);
    }
}

// Usage examples
public class EnumExample {
    public static void main(String[] args) {
        // Basic usage
        Day today = Day.MONDAY;
        System.out.println("Today is " + today);

        // Switch statement with enum
        switch (today) {
            case MONDAY:
                System.out.println("Start of the work week");
                break;
            case FRIDAY:
                System.out.println("TGIF!");
                break;
            default:
                System.out.println("Midweek");
        }

        // Using enum methods
        Planet earth = Planet.EARTH;
        System.out.println("Earth's mass: " + earth.getMass());
        System.out.println("Earth's surface gravity: " + earth.surfaceGravity());

        // Iterating over enum values
        for (Planet planet : Planet.values()) {
            System.out.println(planet.name() + ": " + planet.surfaceGravity());
        }
    }
}

Usage with Pageable

public enum UserSortField {
    ID("id"),
    FIRST_NAME("firstName"),
    LAST_NAME("lastName"),
    EMAIL("email"),
    CREATED_DATE("createdDate");

    private final String fieldName;

    UserSortField(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getFieldName() {
        return fieldName;
    }
}

@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping
    public ResponseEntity<Map<String, Object>> getAllUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "ID") UserSortField sortBy) {
        
        Page<User> userPage = userService.getAllUsers(page, size, sortBy);

        // ... rest of the method remains the same
    }
}

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public Page<User> getAllUsers(int page, int size, UserSortField sortBy) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy.getFieldName()));
        return userRepository.findAll(pageable);
    }
}

Usage with Spring Data JPA

public enum Status {
    ACTIVE, INACTIVE, PENDING
}

import javax.persistence.*;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Enumerated(EnumType.STRING)
    private Status status;

    // getters and setters
}

The @Enumerated annotation is used to specify how the Enum should be persisted in the database. There are two options:

EnumType.ORDINAL: Stores the Enum as an integer (the ordinal value of the Enum constant). EnumType.STRING: Stores the Enum as a string (the name of the Enum constant).

EnumType.ORDINAL

Pros

  • Database efficiency: Stores enums as integers, which typically use less storage space than strings.
  • Potentially faster queries: Integer comparisons are generally faster than string comparisons.
  • Simpler database representation: The database column is a simple integer type.

Cons

  • Fragility to enum order changes: If you add, remove, or reorder enum constants, the ordinal values change, which can corrupt existing data.
  • Less readable in raw database queries: You see numbers instead of meaningful names.
  • Potential for invalid states: If the database contains an integer that doesn’t correspond to any enum constant, it can lead to runtime errors.

EnumType.STRING

Pros

  • Readability: The database stores the actual names of the enum constants, making raw database queries more understandable.
  • Resilience to enum order changes: Adding or reordering enum constants doesn’t affect existing data.
  • Self-documenting: The database schema itself documents the possible enum values.
  • Safety: It’s harder to accidentally introduce invalid states, as any string not matching an enum constant will be rejected.

Cons

  • Less efficient storage: Strings typically use more storage space than integers.
  • Potentially slower queries: String comparisons can be slower than integer comparisons, especially for large datasets.
  • Case sensitivity: By default, the comparison is case-sensitive, which might lead to issues if not handled carefully.

Recommendation

In most cases, EnumType.STRING is the safer and more maintainable choice, despite the slight performance trade-off. The benefits of readability, safety, and resilience to changes usually outweigh the minor efficiency gains of EnumType.ORDINAL.

However, if you’re dealing with a very large dataset where performance and storage efficiency are critical, and you can guarantee that the enum order will never change, EnumType.ORDINAL might be considered.

Best Practices

Default to EnumType.STRING unless you have a compelling reason not to. If using EnumType.ORDINAL, document it clearly and warn about the dangers of changing the enum order. Consider using a custom UserType for more complex enum persistence scenarios. If using EnumType.STRING, be aware of case sensitivity in your database queries.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy