I have an Enum for Days of week (with Everyday, weekend and weekdays) as follows where each entry has an int value.
public enum DaysOfWeek {
Everyday(127),
Weekend(65),
Weekdays(62),
Monday(2),
Tuesday(4),
Wednesday(8),
Thursday(16),
Friday(32),
Saturday(64),
Sunday(1);
private int bitValue;
private DaysOfWeek(int n){
this.bitValue = n;
}
public int getBitValue(){
return this.bitValue;
}
}
Given a TOTAL of any combination of the values, what would be the simplest way to calculate all individual values and make an arraylist from it. For example given the number 56 (i.e. Wed+Thur+Fri), how to calculate the days.
The correct way to represent a collection of enum values is to use an EnumSet. This uses a bit vector internally. But exposing such an implementation detail as in your code is not a good idea. We're doing OO here, not bit-twiddling.
Additionally, you are mixing the concepts of a single value and a collection of values, which will likely lead to headaches down the road.
Example using the DayOfWeek enum built into Java 8 and later.
EnumSet<DayOfWeek> weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY );
Boolean isTodayWeekend = weekend.contains( LocalDate.now().getDayOfWeek() );
As Michael suggested do not expose this implementation detail to the outside world.
Create a static method that converts int bitmask to EnumSet:
public static EnumSet< DaysOfWeek > fromBitValues (
final int origBitMask
)
{
final EnumSet< DaysOfWeek > ret_val =
EnumSet.noneOf( DaysOfWeek.class );
int bitMask = origBitMask;
for ( final DaysOfWeek val : DaysOfWeek.values( ) )
{
if ( ( val.bitValue & bitMask ) == val.bitValue )
{
bitMask &= ~val.bitValue;
ret_val.add( val );
}
}
if ( bitMask != 0 )
{
throw
new IllegalArgumentException(
String.format(
"Bit mask value 0x%X(%d) has unsupported bits " +
"0x%X. Extracted values: %s",
origBitMask,
origBitMask,
bitMask,
ret_val
)
);
}
return ret_val;
}
You may also need a static method that converts an EnumSet to a bit mask, I leave this exercise to the reader.
Also, looking at your enum, Everyday, Weekends and Weekdays do not belong there. They are aggregates of you other DaysOfWeek values and as such should be defined as EnumSets.
Related
I have 3 classes, Human, Date, and Zodiac. In Date I have two int types, month and day. I have normal constructor and getter. In Human I have a String name and a birthday from the type Date.
My Class Date:
public class Date {
private int month;
private int day;
public Date(int month, int day) {
this.month = month;
this.day = day;
}
public int getMonth() { return month;}
public int getDay() {return day;}
My Class Human
public class Human {
private String name;
private Date birthday;
public Human(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() { return name;}
public BirthDate getBirthday() { return birthday;}
In My class Zodiac I have a Main where I created some objects. Then I have a method zodiacToHuman were I give a Human his star sign. But this method didn't work at all. The method has a List as Parameter and returns a Map.
My method in class Zodiac:
public static Map<Human, String> zodiacToHuman(List<Human> humanlist){
Map<Human, String> personSign = new HashMap<>();
Human human;
String sign = "";
int day = Date.getDay();
int month = Date.getMonth();
if (month == 1) {
if (day < 20)
sign = "capricornus";
humanSign.put(human, sign);
else
sign = "aquarius";
humanSign.put(human, sign);
}//and so on
}
This is the error I get:
Non-static method 'getDay()' cannot be referenced from a static context
Non-static method 'getMonth()' cannot be referenced from a static context
Variable Human might not have been initialized
Can someone help me?
You can't do
int day = Date.getDay()
Create an object first of the Date class and use it to get the day and month
Data date = new Date()
int day = date.getDay()
int month = date.getMonth()
Also you haven't initialised your Human class object.
You can write
Human human = new Human(some_day, some_month)
Let's change the name of Date to more precise MonthWithDay.
We can shorten the code of that class by making it a record. By default, the implicitly created getter methods are named the same as the member field name.
public record MonthWithDay( int month , int day ) { }
Similarly we can define your Human class as a record in one short line.
public record Human( String name , MonthWithDay monthDayWhenBorn ) { }
Regarding your method to determine zodiac:
public static Map<Human, String> zodiacToHuman(List<Human> humanlist){ …
… there is no need for static. In your scenario, that seems like a reasonable feature on your Human class.
Tip: In object-oriented programming, using static is not object-oriented. Try to minimize use of static. Use as a last resort only.
public record Human( String name , MonthWithDay monthDayWhenBorn )
{
public String zodiac ( )
{
int day = this.monthDayWhenBorn.day();
int month = this.monthDayWhenBorn.month();
if ( month == 1 )
{
if ( day < 20 )
{ return "capricornus"; }
else
{ return "aquarius"; }
}
return "other";
}
}
Populate some example data.
List < Human > humans =
List.of(
new Human( "Alice" , new MonthWithDay( 1 , 11 ) ) ,
new Human( "Alice" , new MonthWithDay( 1 , 22 ) ) ,
new Human( "Carol" , new MonthWithDay( 11 , 27 ) )
);
Create your map of human to zodiac.
Map< Human , String > mapOfHumanToZodiac = new HashMap<>() ;
Loop through each Human object, interrogate for its zodiac, and place into our map.
for ( Human human : humans )
{
mapOfHumanToZodiac.put( human , human.zodiac() );
}
Dump to console.
System.out.println( "mapOfHumanToZodiac = " + mapOfHumanToZodiac );
mapOfHumanToZodiac = {Human[name=Alice, monthDayWhenBorn=MonthWithDay[month=1, day=11]]=capricornus, Human[name=Alice, monthDayWhenBorn=MonthWithDay[month=1, day=22]]=aquarius, Human[name=Carol, monthDayWhenBorn=MonthWithDay[month=11, day=27]]=other}
By the way, in real work we would define an enum to represent each of the zodiac signs rather than use mere strings. Doing so provides type-safety, ensures valid values (avoids errors from typos in the strings), and makes the code more self-documenting.
java.time
Java comes with an industry-leading framework of date-time classes, found in the java.time package. These classes include a MonthDay class. So no need to invent your own. We can delete your MonthWithDay class.
Tweak the Human class.
public record Human( String name , MonthDay monthDayWhenBorn ) // <-- Use java.time.MonthDay class.
{
public String zodiac ( )
{
int day = this.monthDayWhenBorn.getDayOfMonth(); // <-- Use java.time.MonthDay class.
int month = this.monthDayWhenBorn.getMonthValue(); // <-- Use java.time.MonthDay class.
if ( month == 1 )
{
if ( day < 20 )
{ return "capricornus"; }
else
{ return "aquarius"; }
}
return "other";
}
}
Change how we create the sample data.
List < Human > humans =
List.of(
new Human( "Alice" , MonthDay.of( 1 , 11 ) ) , // <-- Use java.time.MonthDay class.
new Human( "Alice" , MonthDay.of( 1 , 22 ) ) ,
new Human( "Carol" , MonthDay.of( 11 , 27 ) )
);
And we get the same results.
Errors and reasons
Variable Human might not have been initialized
Its not a error its a warning that saying human variable might be null as you have only decalre the variable human. To initialize either you need to create an instance or assign null to it
Human human = new Human(YOUR VALUES);
//or
Human human = null;
Non-static method 'getDay()' cannot be referenced from a static context
Non-static method 'getMonth()' cannot be referenced from a static context
You cannot access public methods of a class directly without creating an object.
NOTE
As per my understanding you are giving each human a sign value.You can achive the same while you are creating each human object and later on create a map from it.
Eg:
public class Human {
private String name;
private Date birthday;
private String sign;
public Human(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
assignZodiac();
}
private void assignZodiac(){
String sign = "";
//getting birhday month and day values
int day = birthday.getDay();
int month = birthday.getMonth();
// your logic of assignment
if (month == 1) {
if (day < 20)
sign = "capricornus";
else
sign = "aquarius";
}//and so on
}
//getter setter
}
Now you can create a map from the list. eg:
// human list has been already created
Map<Human,String> humanSign=newHasmap<>();
for(Human human : humanList) {
humanSign.put(human,human.getSign()) //asuming getSign is the getter for sign filed in Human.
}
Also I would suggest you to change Date class name to something else since java already has a class of the same name. It's just for naming convection
As I understand the humanList contains entries of Human Objects.
You should try iterating over the list, like so
public static Map<Human, String> zodiacToHuman(List<Human> humanlist) {
Map<Human, String> personSign = new HashMap<>();
for (Human human : humanList) {
String sign = "";
int day = human.getBirthday().getDay();
int month = human.getBirthday().getMonth();
if (month == 1) {
if (day < 20) {
sign = "capricornus";
} else {
sign = "aquarius";
}
} //and so on
humanSign.put(human, sign);
}
}
If I have some many constants like shortName="rule1"; descrition="description1"; rule2/description2; rule3 / description3? and I need to find out the description for a certain shortName, given by a parameter, what would be the best way to do this?
Would it be a enum like this?
public enum Description {
RULE1 ("rule1", "description1"),
RULE2 ("rule2", "description2"),
RULE3 ("rule3", "description3");
private final String shortName;
private final String description;
Description(String shortName, String description) {
this.shortName= shortName;
this.description = description;
}
}
But if I have a method like private String getDescription(String shortName) how can I use the enum to get the description of a shortName declared in enum?
I can't use constants because I have ~200 definitions like this.
An enum defines a type
You asked:
and I need to find out the description for a certain shortName, given by a parameter, what would be the best way to do this?
Would it be a enum like this?
Yes, if those rule1, rule2, and such are all conceptually members of the same type.
For example:
public enum Pet{ DOG , CAT , BIRD , HAMSTER }
public enum Flavor{ VANILLA , CHOCOLATE, STRAWBERRY }
public enum Color{ BURLYWOOD , CORNFLOWER_BLUE, DARK_SLATE_GREY }
Using an enum such as those means you can write other code that is type-safe, ensures valid values, and is more self-documenting.
pictureMaker.displayIceCreamCone( Flavor.CHOCOLATE )
On the other hand, if your values are unrelated, just a hodgepodge of various strings for various purposes, I would use string constants. And if they are resources for localization, use specific localization tools.
You asked:
But if I have a method like private String getDescription(String shortName) how can I use the enum to get the description of a shortName declared in enum?
That question suggests you are passing around the text of the short name as a key to finding the description. But you should not be passing around some string, you should be passing around the enum object. Take, for example, java.time.DayOfWeek enum. You should be passing around DayOfWeek.SATURDAY rather than "SATURDAY".
But if you must, you could implement a static method on your enum to loop through all the enum objects to find one that matches.
// Utility method to loop all the enum objects until finding a match.
public static String getLongStringForShortName ( String shorty )
{
String result = null;
if ( RULE1.shortName.equals( shorty ) ) { result = RULE1.description; }
if ( RULE2.shortName.equals( shorty ) ) { result = RULE2.description; }
if ( RULE3.shortName.equals( shorty ) ) { result = RULE3.description; }
return result;
}
Or, in alternative syntax, use streams to softcode references to each and every enum object.
// Utility method to loop all the enum objects until finding a match.
public static String getLongStringForShortName ( String shorty )
{
String result = "";
Optional < Description > optionalDesc = Arrays.stream( Description.values() ).filter( ( Description d ) -> d.description.equals( shorty ) ).findFirst();
if ( optionalDesc.isPresent() ) { result = optionalDesc.get().description; }
return result;
}
Map
But that code has a smell about it. You likely have the wrong data structure if you do this often, or this is your main purpose. This looks like we are abusing the enum where instead should be using a Map.
Map < String, String > descriptions =
Map.of(
"rule1" , "description1" ,
"rule2" , "description2" ,
"rule3" , "description3"
)
;
String longDesc = descriptions.get( "rule1" );
EnumMap
You could mix the concepts of enum and map. Your Question lacks the context to know if this is right for you or not. But FYI…
Change your enum class to just this:
package work.basil.example;
public enum Description
{
RULE1, RULE2, RULE3;
}
Use an EnumMap to map each of these enum objects to some other object such as a string.
Map < Description, String > descriptionToLongForm = new EnumMap <>( Description.class );
descriptionToLongForm.put( Description.RULE1 , "description1" );
descriptionToLongForm.put( Description.RULE2 , "description2" );
descriptionToLongForm.put( Description.RULE3 , "description3" );
String longDesc = descriptionToLongForm.get( Description.RULE2 );
Or, in alternative syntax, using Map.of. This produces a non-modifiable map.
Map < Description, String > descriptionToLongForm =
Map.of(
Description.RULE1 , "description1" ,
Description.RULE2 , "description2" ,
Description.RULE3 , "description3"
);
String longDesc = descriptionToLongForm.get( Description.RULE2 );
I'm writing a program to sort datetimes by date.
There is a DateTime beginning and a DateTime end.
These are put into their own object from user input.
The DateTime beginning and the DateTime end make up their own term.
So each term has an object of its own with a DateTime beginning and a DateTime end.
What I want to do is to sort all DateTime beginning and all DateTime end by date.
How can I do this? I'm thinking about a comperator but I can't seem to do this on custom objects.
So lets say user imputs one beginning date of 01/01/2000 and one end date of 01/01/2002. This makes up one term.
The user then imputs a second term consisting of a beginning date of 01/01/2001 and an end date of 01/01/2003.
What I now want to do is to sort the dates and make the three new terms which would be:
beginning 01/01/2000 end 01/01/2001
beginning 01/01/2001 end 01/01/2002
beginning 01/01/2002 end 01/01/2003
I'm stuck on how to proceed with this, any ideas?
Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.
Try:
public static void main(String[] args) {
List<YourClass> list = new ArrayList<>();
list.add(new YourClass(new Date(100000000), new Date(200000000)));
list.add(new YourClass(new Date(150000000), new Date(250000000)));
list.add(new YourClass(new Date(50000000), new Date(300000000)));
System.out.println(list);
List<Date> dates = new ArrayList<>();
for (YourClass yc : list){
if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
if (!dates.contains(yc.end)) dates.add(yc.end);
}
Collections.sort(dates);
List<YourClass> list2 = new ArrayList<>();
for (int i=0; i < dates.size() -1; i++){
list2.add(new YourClass(dates.get(i), dates.get(i+1)));
}
System.out.println(list2);
}
public static class YourClass {
Date beginning;
Date end;
public YourClass(Date beginning, Date end) {
this.beginning = beginning;
this.end = end;
}
#Override
public String toString() {
return "\n" + beginning + " -> " + end ;
}
}
tl;dr
What I want to do is to sort all DateTime beginning and all DateTime end by date.
You can do one or the other but not both.
To sort by start date (seems sensible in practice), implement compareTo method.
return this.getDateRange().getStart().compareTo( thatStart );
To sort by stop date (I do not see any sense in this), implement the Comparator interface.
return
t1.getDateRange().getEnd().compareTo(
t2.getDateRange().getEnd()
)
;
LocalDate
As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.
LocalDateRange
As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.
Comparable
On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.
The LocalDate class implements compareTo, no we don’ have to.
#Override
public int compareTo ( Object o ) {
if ( this == o ) return 0;
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}
See the Java Tutorial on object-ordering.
Sort by stop date
Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.
#Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}
Example class
Here is an example Term class. May not be production-quality code, but should get you going in the right direction.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
public class Term implements Comparable {
private UUID id;
private LocalDateRange dateRange;
// Constructor
public Term ( LocalDate start , LocalDate stop , UUID id ) {
Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
}
this.id = id;
this.dateRange = LocalDateRange.of( start , stop );
}
// Alternative constructor.
public Term ( LocalDateRange dateRange , UUID id ) {
this( dateRange.getStart() , dateRange.getEnd() , id );
}
// --------| Object |-------------------------
#Override
public String toString ( ) {
return "Term{ " +
"id=" + id +
" | dateRange=" + dateRange +
" }";
}
public UUID getId ( ) {
return id;
}
public LocalDateRange getDateRange ( ) {
return dateRange;
}
#Override
public boolean equals ( Object o ) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
Term term = ( Term ) o;
return this.getId().equals( term.getId() );
}
#Override
public int hashCode ( ) {
return Objects.hash( this.getId() );
}
#Override
public int compareTo ( Object o ) {
if ( this == o ) return 0; // If same object.
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}
static public class StopDateComparator implements Comparator < Term > {
#Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}
}
}
Try it.
public static void main ( String[] args ) {
Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
System.out.println( "Before natural sort: " + terms );
Collections.sort( terms );
System.out.println( "After natural sort: " + terms );
Collections.sort( terms , new Term.StopDateComparator() );
System.out.println( "After Comparator sort: " + terms );
}
Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]
After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]
After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]
abuts
If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.
The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.
I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.
With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.
class Interval implements Comparable<Interval> {
private final LocalDateTime start;
private final LocalDateTime end;
public Interval(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
public int compareTo(Interval that) {
return this.start.compareTo(that.start);
}
public boolean overlaps(Interval that) {
return !this.isBefore(that) && !this.isAfter(that);
}
public boolean contains(Interval that) {
return this.start.isBefore(that.start) && this.end.isAfter(that.end);
}
public boolean isBefore(Interval that) {
return this.end.isBefore(that.start);
}
public boolean isAfter(Interval that) {
return this.start.isAfter(that.end);
}
public Set<Interval> fragment(Interval that) {
if (that.start.isBefore(this.start)) {
return that.fragment(this);
}
Set<Interval> result = new HashSet<>();
if (this.end.isBefore(that.start)) {
result.add(this);
result.add(that);
result.add(new Interval(this.end, that.start));
} else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
result.add(new Interval(this.start, that.start);
result.add(new Interval(that.start, this.end);
result.add(new Interval(this.end, that.end));
} else if (this.end.isAfter(that.end)) {
result.add(new Interval(this.start, that.start);
result.add(new Interval(that);
result.add(new Interval(that.end, this.end));
}
}
}
You can now keep them sorted, since Intervals are comparable by start date.
Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.
You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.
I have variables of type long: hour_6days, hour_7days, hour_8days and hour_13days.
I have a string array:
String[] jj = rule.split(del);
where jj[0] contains the one of the numbers 6 or 7 or8 or 13.
How to change the above long variables according to the value in jj[0] ?
For example, how can I write the below, such that right hand side of the assignment is equivalent to the left hand side variable like:
hour_6days = "hour_"+jj[0]+"6days"; //this is invalid as hour_6days is of long type.
To be more clear,
If jj[0] contains 6, then I will use long variable's hour_6days value. If jj[0] contains 7, then I will use the long variable's hour_7days value.
The values I am using to set certain TextView like:
TextView tt2 = (TextView) v.findViewById(R.id.th3);
tt2.setText(hour_7days);
UPDATE:
I want to reuse the code in order to avoid multiple conditions. As said, in some conditions I am using tt2.setText(hour_7days); and in some other conditions I am using tt2.setText(hour_6days); and so on. I want to avoid the conditions and just simple use tt2.setText(hour_6_or_7_or_8days).
Try using a Map, HashMap is a possible choice.
HashMap<Integer, Long> dayValues = new HashMap<Integer, Long>();
dayValues.put(6, <put long value for 6 days here>);
dayValues.put(7, <put long value for 7 days here>);
dayValues.put(8, <put long value for 8 days here>);
dayValues.put(13, <put long value for 13 days here>);
...
tt2.setText(dayValues.get(jj[0]).toString());
This will use the integer value in jj[0] to get the corresponding string value from the map and set it into tt2.
If I understand you right you would use enum, like:
public enum EHourDay{
hour_6days(6), // actually I would use Upper case
hour_7days(7),
hour_8days(8),
hour_13days(13);
public static EHourDay
FromIntToEnum(
int value ) throws Exception
{
for ( EHourDay c : EHourDay.values() ) {
if ( c.mId == value ) {
return c;
}
}
throw new Exception( new StringBuilder("Illegal EHourDay: ").append(value).toString() );
}
public int
FromEnumToInt() {
return mId;
}
private EHourDay( int id )
{
mId = id;
}
private int mId;
}
Main
public static void main(String[] args) throws NumberFormatException, Exception {
String rule = "6 7 8 13";
String[] jj = rule.split(" ");
for(String str : jj){
EHourDay hourDay = EHourDay.FromIntToEnum(Integer.parseInt(str));
System.out.println(hourDay);
}
}
After you can type something like:
tt2.setText(EHourDay.FromIntToEnum(Integer.parseInt(str)));
What if I'll use switch in getByIntValue()? Is it really neccessary to use a SparseArray?
public enum Gender {
Unknown(0),
Male(1),
Female(2);
private static final SparseArray<Gender> lookupTable = new SparseArray<Gender>();
static {
for (final Gender gender : EnumSet.allOf(Gender.class)) {
lookupTable.put(gender.intValue, gender);
}
}
private final int intValue;
public static Gender getByIntValue(int val) {
return lookupTable.get(val);
}
private Gender(int intValue) {
this.intValue = intValue;
}
public int getIntValue() {
return intValue;
}
}
Since your int values go from 0 to 2, without hole, you could indeed simply use an array. A switch would also be fine, although it would probably be slightly slower than an array lookup. But unless you call the method billions of times, it won't make any noticeable difference. Use what you find the clearest and easiest to understand and maintain.
If you have posted realistic int values, then you don't need to set them explicitly on each enum member, and don't need switch. Just use
Gender.values()[intValue]
List.copyOf( EnumSet.allOf( Gender.class ) )
Caveat: This exercise in optimization seems silly for all but the most extreme scenario, as mentioned by JB Nizet. For real work, I would probably recommend the solution seen in the Answer by Marko Topolnik. But, for fun, I swung a bat at this ball.
Seems the goal is to render a static unmodifiable collection with very fast access by the given numbers 0, 1, 2.
As of Java 10, we have these new implemented (“default”) methods on the List interface: List.of & List.copyOf. These produce an unmodifiable collection. Though the backing implementation is undocumented and subject to change, I will assume it is something akin to an array with similar performance. Performance might even be faster than a conventional array, if the backing implementation detected the presence of an EnumSet and used some kind of bit vector.
I populate the List by passing an EnumSet to List.copyOf( Collection ).
So, this:
private static final SparseArray<Gender> lookupTable = new SparseArray<Gender>();
static {
for (final Gender gender : EnumSet.allOf(Gender.class)) {
lookupTable.put(gender.intValue, gender);
}
}
…becomes this:
private static final List < Gender > lookupTable = List.copyOf( EnumSet.allOf( Gender.class ) );
Entire class, with main for demo.
package com.basilbourque.example;
import java.util.EnumSet;
import java.util.List;
public enum Gender {
UNKNOWN( 0 ),
MALE( 1 ),
FEMALE( 2 );
private static final List < Gender > lookupTable = List.copyOf( EnumSet.allOf( Gender.class ) );
private final int intValue;
public static Gender getByIntValue ( int val ) {
return lookupTable.get( val );
}
public int getIntValue () {
return intValue;
}
// Constructor
private Gender ( int intValue ) {
this.intValue = intValue;
}
public static void main ( String[] args ) {
// Testing.
System.out.println( Gender.UNKNOWN.intValue );
System.out.println( Gender.getByIntValue( 0 ) );
System.out.println( "----" );
System.out.println( Gender.MALE.intValue );
System.out.println( Gender.getByIntValue( 1 ) );
System.out.println( "----" );
System.out.println( Gender.FEMALE.intValue );
System.out.println( Gender.getByIntValue( 2 ) );
}
}
When run.
0
UNKNOWN
1
MALE
2
FEMALE
By the way, as the biological default, FEMALE should come before MALE.