Java set witth enum values - java

I have a java enum as
public enum Month {
JANUARY("01. January")
,FEBRUARY("02. February")
, MARCH("03. March")
, APRIL("04. April")
, MAY("05. May")
, JUNE("06. June")
, JULY("07. July")
, AUGUST("08. August")
, SEPTEMBER("09. September")
, OCTOBER("10. October")
, NOVEMBER("11. November")
, DECEMBER("12. December");
private final String displayName;
Month(final String display)
{
this.displayName = display;
}
#Override public String toString()
{
return this.displayName;
}
};
Also I have a DTO Object which is
public class SampleDTO {
private int variable1;
private Set<String> monthName;
public int getVariable1() {
return variable1;
}
public void setVariable1(int variable1) {
this.variable1 = variable1;
}
public Set<String> getMonthName() {
return monthName;
}
public void setMonthName(Set<String> monthName) {
this.monthName = monthName;
}
}
Last I have a method with input parameter as SampleDTO, Is there a way I can force that when a string is added to the monthName , it always comes from the valid values of the enum. for example adding "dfkjahdkjfadf" to the set should not be permitted

Change Set<String> to Set<Month> so that it can only contain Month enum instances. Making sure it is a legal month seems to be part of your contract, so you have to enforce it inside SampleDTO.

You might used Set<Month> instead of Set<String>, for example:
public class SampleDTO {
. ...
private Set<Month> month;
...
}

Related

What data structure should i load this data into and how?

In the first part of my code I am reading data from a file and putting the fields into variables like this
Date date = rs.getDate(1);
Integer flightnumber = rs.getInt("FlightNumber");
Integer passengers = rs.getInt("Passengers");
so I need to put these variables into an ArrayList for example and then write a method that compares two variables with the ones in the list I created and returns an int being the passengers.
public int getPassengerNumbersFor(int flightNumber, LocalDate date)
The tricky part is that I cannot create any new classes and there isn't any getFlightNumber/ getDate implemented nor am I allowed to code one. I have been told that a HashMap can be used but in this case I would have one key and two values which wouldn't work (passengers is key, flightnumber and date are values maybe).
How can I store these 3 values and then write my method?
If you were "allowed" to create classes, I would suggest an immutable class:
public class Flight {
private final LocalDate localDate;
private final int number;
private final List<Passenger> passengers;
public Flight(LocalDate localDate, int number, List<Passenger> passengers) {
this.localDate = localDate;
this.number = number;
this.passengers = List.copyOf(passengers);
}
public LocalDate getLocalDate() {
return localDate;
}
public int getNumber() {
return number;
}
public List<Passenger> getPassengers() {
return passengers;
}
public int getPassengersNumber() {
return passengers.size();
}
...
}
Note the usage of the new Date-Time API.
And then you could have another class for all the flights:
public class Flights {
private final List<Flight> flights;
public Flights(List<Flight> flights) {
this.flights = new ArrayList<>(flights);
}
public Flight getFlight(LocalDate localDate, int number) {
return flights.stream()
.filter(flight -> flight.getLocalDate().equals(localDate))
.filter(flight -> flight.getNumber() == number)
.findAny()
.orElseThrow(InvalidFlightException::new);
}
public void addFlight(Flight flight) {
flights.add(flight);
}
...
}

I want to make universal method in CLASS for all enums

public class TableContent {
public static String EXCEL_SHEET_NAME = Nit.THEAD.getName();
public static String FILENAME= Nit.FILENAME.getName();
public enum Nit {
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
public String getName() {
return name;
}
private Nit(String name) {
this.name = name;
}
public static Nit getNitHeadByName(String name)
{
Nit[] nit=Nit.values();
if(nit==null)
{
return null;
}
for(Nit nitHead:nit)
{
if(nitHead.getName().equals(name))
return nitHead;
}
return null;
}
public enum NitWorkOrder {
}
public enum NitList {
}
My objective is:
I want to export excel sheet from my application, every time I need to hardcode the table headings, which was not good programming practice.
So I use enum to overcome the hardcode problem. Now there are different table heading according to the list, then I enclosed all the required ENUMS in single class.
I used to write getXXXByName() and getXXXByValue() to access the enum, by name or by value.
But he problem is I need to write getXXXByName() and getXXXByValue() everytime inside each enum. I want to write these methods inside the class and outside the enums, and access those methods with the help of class name.
I just want to declare my constants inside enum.
Please kindly suggest me an idea or a way so I can make this method universal which will work for each and every enum. I want to write these methods in such a way so it can be accessed for all enums enclosed in my class. I thought about generics but I have little knowledge.
You can use generics to push functionality up to a parent class by telling the parent class that the type is an enum that implements an interface.
// Use an interface to inform the super class what the enums can do.
public interface Named {
public String getName();
}
// Super class of all Tables.
public static class Table<E extends Enum<E> & Named> {
private final Class<E> itsClass;
private final String sheetName;
private final String fileName;
public Table(Class<E> itsClass) {
this.itsClass = itsClass;
// Walk the enum to get filename and sheet name.
String sheetName = null;
String fileName = null;
for ( E e: itsClass.getEnumConstants() ){
if ( e.name().equals("FILENAME")) {
fileName = e.getName();
}
if ( e.name().equals("THEAD")) {
sheetName = e.getName();
}
}
this.sheetName = sheetName;
this.fileName = fileName;
}
// Use the interface and the enum details to do your stuff.
public E getByName (String name) {
for ( E e: itsClass.getEnumConstants() ){
if ( e.getName().equals(name)) {
return e;
}
}
return null;
}
}
// Extend Table and tell it about your enum using the super constructor.
public static class TableContent extends Table<TableContent.Nit> {
public TableContent() {
super(TableContent.Nit.class);
}
public enum Nit implements Named{
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
Nit(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}

How to enable enum inheritance

I'm writing a library, which has a predefined set of values for an enum.
Let say, my enum looks as below.
public enum EnumClass {
FIRST("first"),
SECOND("second"),
THIRD("third");
private String httpMethodType;
}
Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.
After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.
What would be the best approach to achieve this?
You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.
However, enums can implement interfaces.
What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.
Then your enum values would be referred to by their common interface.
In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.
That would force implementing enums to provide an implementation for that method.
This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.
Self-contained example (don't mind the lazy names here)
package test;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<HTTPMethodConvertible> blah = new ArrayList<>();
blah.add(LibraryEnum.FIRST);
blah.add(ClientEnum.BLABLABLA);
for (HTTPMethodConvertible element: blah) {
System.out.println(element.getHTTPMethodType());
}
}
static interface HTTPMethodConvertible {
public String getHTTPMethodType();
}
static enum LibraryEnum implements HTTPMethodConvertible {
FIRST("first"),
SECOND("second"),
THIRD("third");
String httpMethodType;
LibraryEnum(String s) {
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
static enum ClientEnum implements HTTPMethodConvertible {
FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
String httpMethodType;
ClientEnum(String s){
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
}
Output
first
POST
Enums are not extensible. To solve your problem simply
turn the enum in a class
create constants for the predefined types
if you want a replacement for Enum.valueOf: track all instances of the class in a static map
For example:
public class MyType {
private static final HashMap<String,MyType> map = new HashMap<>();
private String name;
private String httpMethodType;
// replacement for Enum.valueOf
public static MyType valueOf(String name) {
return map.get(name);
}
public MyType(String name, String httpMethodType) {
this.name = name;
this.httpMethodType = httpMethodType;
map.put(name, this);
}
// accessors
public String name() { return name; }
public String httpMethodType() { return httpMethodType; }
// predefined constants
public static final MyType FIRST = new MyType("FIRST", "first");
public static final MyType SECOND = new MyType("SECOND", "second");
...
}
Think about Enum like a final class with static final instances of itself. Of course you cannot extend final class, but you can use non-final class with static final instances in your library. You can see example of this kind of definition in JDK. Class java.util.logging.Level can be extended with class containing additional set of logging levels.
If you accept this way of implementation, your library code example can be like:
public class EnumClass {
public static final EnumClass FIRST = new EnumClass("first");
public static final EnumClass SECOND = new EnumClass("second");
public static final EnumClass THIRD = new EnumClass("third");
private String httpMethodType;
protected EnumClass(String name){
this.httpMethodType = name;
}
}
Client application can extend list of static members with inheritance:
public final class ClientEnum extends EnumClass{
public static final ClientEnum CUSTOM_FIRST = new ClientEnum("custom_first");
public static final ClientEnum CUSTOM_SECOND = new ClientEnum("custom_second");
private ClientEnum(String name){
super(name);
}
}
I think that this solution is close to what you have asked, because all static instances are visible from client class, and all of them will satisfy your generic wildcard.
We Fixed enum inheritance issue this way, hope it helps
Our App has few classes and each has few child views(nested views), in order to be able to navigate between childViews and save the currentChildview we saved them as enum inside each Class.
but we had to copy paste, some common functionality like next, previous and etc inside each enum.
To avoid that we needed a BaseEnum, we used interface as our base enum:
public interface IBaseEnum {
IBaseEnum[] getList();
int getIndex();
class Utils{
public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
if (index + 1 < list.length) {
return list[index + 1];
} else if(isCycling)
return list[0];
else
return null;
}
public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
IBaseEnum previous;
if (index - 1 >= 0) {
previous = list[index - 1];
}
else {
if (isCycling)
previous = list[list.length - 1];
else
previous = null;
}
return previous;
}
}
}
and this is how we used it
enum ColorEnum implements IBaseEnum {
RED,
YELLOW,
BLUE;
#Override
public IBaseEnum[] getList() {
return values();
}
#Override
public int getIndex() {
return ordinal();
}
public ColorEnum getNext(){
return (ColorEnum) new Utils().next(this,false);
}
public ColorEnum getPrevious(){
return (ColorEnum) new Utils().previous(this,false);
}
}
you could add getNext /getPrevious to the interface too
#wero's answer is very good but has some problems:
the new MyType("FIRST", "first"); will be called before map = new HashMap<>();. in other words, the map will be null when map.add() is called. unfortunately, the occurring error will be NoClassDefFound and it doesn't help to find the problem. check this:
public class Subject {
// predefined constants
public static final Subject FIRST;
public static final Subject SECOND;
private static final HashMap<String, Subject> map;
static {
map = new HashMap<>();
FIRST = new Subject("FIRST");
SECOND = new Subject("SECOND");
}
private final String name;
public Subject(String name) {
this.name = name;
map.put(name, this);
}
// replacement for Enum.valueOf
public static Subject valueOf(String name) {
return map.get(name);
}
// accessors
public String name() {
return name;
}

Integer type reference String type value

two class:
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
I want use reflect to implment like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("string here");
Integer type reference String type value.
Generics in Java are not used at runtime, so as far as the java runtime is concerned you're ID field is of type Object and so can be set to any value regardless of the generics. That said, doing so is a bad idea since anything assuming the generic contract will fail.
You can set the field by reflection as follows:
BeanDo beanDo = new BeanDo();
Method method = BeanDo.getClass().getMethod("setId", Object.class);
method.invoke(beanDo, "SomeRandomString");
That said, doing this is an extreamly bad idea because any code compile against BeanDo will assume that the id is an integer not a String. So any code like beanDo.getId() will fail with a class cast exception because it's not actually an integer.
Like the other posters, I'm somewhat in the dark about what you're trying to achieve.
Something like this?
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public void setId(String id) {
setId(Integer.parseInt(id));
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
Now you can use something like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("2");
What about this:
BeanDo beando = new BeanDo();
beando.setId("string there".hashCode());
I don't quite get what you mean with "I want to use reflect to implement this" though.
I guess you want something like this:
BeanDo doer = ... // get it from somewhere
String id = ... // get it from somewhere else too.
// and you want to set id to the doer bean.
reflectionMagicSetId( doer, id );
And have the method like:
private void reflectionMagicSetId( BandDo doer, String id ) {
/// do some magic here?
}
If that's what you want, what I give you works perfectly.
private void reflectionMagicSetId( BandDo doer, String id ) {
doer.setId( id == null ? 0 : id.hashCode() );
}
If you wann use integer then parse the string to integer as it will contain the integer and use that integer in the calling function argument
It seems like a subclass about the only way to be able to set a string, but still guarantee that anyone who's already calling getId() gets the Integer they expect. Something like this:
public class StringBeanDo extends BeanDo {
private String stringId;
public String getStringId()
{
return stringId;
}
public void setId( Integer val )
{
super.setId( val );
stringId = Integer.toString( val );
}
public void setId( String str )
{
stringId = str;
super.setId( convertStringToInteger( str )); // Do this however you like.
}
}
The implementation of convertStringToInteger would be up to you (it'll depend on what this ID is being used for). The key here is that you're maintaining TWO IDs, and keeping them in sync, so that older code can still limp along to some extent.

How can I lookup a Java enum from its String value?

I would like to lookup an enum from its string value (or possibly any other value). I've tried the following code but it doesn't allow static in initialisers. Is there a simple way?
public enum Verbosity {
BRIEF, NORMAL, FULL;
private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();
private Verbosity() {
stringMap.put(this.toString(), this);
}
public static Verbosity getVerbosity(String key) {
return stringMap.get(key);
}
};
Use the valueOf method which is automatically created for each Enum.
Verbosity.valueOf("BRIEF") == Verbosity.BRIEF
For arbitrary values start with:
public static Verbosity findByAbbr(String abbr){
for(Verbosity v : values()){
if( v.abbr().equals(abbr)){
return v;
}
}
return null;
}
Only move on later to Map implementation if your profiler tells you to.
I know it's iterating over all the values, but with only 3 enum values it's hardly worth any other effort, in fact unless you have a lot of values I wouldn't bother with a Map it'll be fast enough.
You're close. For arbitrary values, try something like the following:
public enum Day {
MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;
private final String abbreviation;
// Reverse-lookup map for getting a day from an abbreviation
private static final Map<String, Day> lookup = new HashMap<String, Day>();
static {
for (Day d : Day.values()) {
lookup.put(d.getAbbreviation(), d);
}
}
private Day(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}
with Java 8 you can achieve with this way:
public static Verbosity findByAbbr(final String abbr){
return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}
#Lyle's answer is rather dangerous and I have seen it not work particularly if you make the enum a static inner class. Instead I have used something like this which will load the BootstrapSingleton maps before the enums.
Edit this should not be a problem any more with modern JVMs (JVM 1.6 or greater) but I do think there are still issues with JRebel but I haven't had a chance to retest it.
Load me first:
public final class BootstrapSingleton {
// Reverse-lookup map for getting a day from an abbreviation
public static final Map<String, Day> lookup = new HashMap<String, Day>();
}
Now load it in the enum constructor:
public enum Day {
MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;
private final String abbreviation;
private Day(String abbreviation) {
this.abbreviation = abbreviation;
BootstrapSingleton.lookup.put(abbreviation, this);
}
public String getAbbreviation() {
return abbreviation;
}
public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}
If you have an inner enum you can just define the Map above the enum definition and that (in theory) should get loaded before.
And you can't use valueOf()?
Edit: Btw, there is nothing stopping you from using static { } in an enum.
In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:
public enum Vebosity {
BRIEF("BRIEF"),
NORMAL("NORMAL"),
FULL("FULL");
private String value;
private Verbosity(final String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
private static ImmutableMap<String, Verbosity> reverseLookup =
Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);
public static Verbosity fromString(final String id) {
return reverseLookup.getOrDefault(id, NORMAL);
}
}
With the default you can use null, you can throw IllegalArgumentException or your fromString could return an Optional, whatever behavior you prefer.
since java 8 you can initialize the map in a single line and without static block
private static Map<String, Verbosity> stringMap = Arrays.stream(values())
.collect(Collectors.toMap(Enum::toString, Function.identity()));
public enum EnumRole {
ROLE_ANONYMOUS_USER_ROLE ("anonymous user role"),
ROLE_INTERNAL ("internal role");
private String roleName;
public String getRoleName() {
return roleName;
}
EnumRole(String roleName) {
this.roleName = roleName;
}
public static final EnumRole getByValue(String value){
return Arrays.stream(EnumRole.values()).filter(enumRole -> enumRole.roleName.equals(value)).findFirst().orElse(ROLE_ANONYMOUS_USER_ROLE);
}
public static void main(String[] args) {
System.out.println(getByValue("internal role").roleName);
}
}
Perhaps, take a look at this. Its working for me.
The purpose of this is to lookup 'RED' with '/red_color'.
Declaring a static map and loading the enums into it only once would bring some performance benefits if the enums are many.
public class Mapper {
public enum Maps {
COLOR_RED("/red_color", "RED");
private final String code;
private final String description;
private static Map<String, String> mMap;
private Maps(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return name();
}
public String getDescription() {
return description;
}
public String getName() {
return name();
}
public static String getColorName(String uri) {
if (mMap == null) {
initializeMapping();
}
if (mMap.containsKey(uri)) {
return mMap.get(uri);
}
return null;
}
private static void initializeMapping() {
mMap = new HashMap<String, String>();
for (Maps s : Maps.values()) {
mMap.put(s.code, s.description);
}
}
}
}
Please put in your opinons.
If you want a default value and don't want to build lookup maps, you can create a static method to handle that.
This example also handles lookups where the expected name would start with a number.
public static final Verbosity lookup(String name) {
return lookup(name, null);
}
public static final Verbosity lookup(String name, Verbosity dflt) {
if (StringUtils.isBlank(name)) {
return dflt;
}
if (name.matches("^\\d.*")) {
name = "_"+name;
}
try {
return Verbosity.valueOf(name);
} catch (IllegalArgumentException e) {
return dflt;
}
}
If you need it on a secondary value, you would just build the lookup map first like in some of the other answers.
You can define your Enum as following code :
public enum Verbosity
{
BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
private int value;
public int getValue()
{
return this.value;
}
public static final Verbosity getVerbosityByValue(int value)
{
for(Verbosity verbosity : Verbosity.values())
{
if(verbosity.getValue() == value)
return verbosity ;
}
return ACTION_NOT_VALID;
}
#Override
public String toString()
{
return ((Integer)this.getValue()).toString();
}
};
See following link for more clarification
You can use the Enum::valueOf() function as suggested by Gareth Davis & Brad Mace above, but make sure you handle the IllegalArgumentException that would be thrown if the string used is not present in the enum.

Categories

Resources