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.
Related
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 working on some homework programs and I'm required to do stuff in Java using functional programming principles as much as possible. These are the important bits of a program that receives a list of numbers and prints the even ones:
public static void main( String args[ ] )
{
ArrayList<Double> listEven = new ArrayList<Double>();
inputRecursion( );
outputRecursion( );
}
public static void inputRecursion( )
{
Scanner in = new Scanner( System.in );
if( in.hasNextDouble() )
{
if( (in.nextDouble() % 2) == 0 )
{
listEven.add( in.nextDouble() );
}
inputRecursion( );
}
}
public static void outputRecursion( )
{
Iterator<Double> it = listEven.iterator();
if( it.hasNext() )
{
System.out.println( it.next() );
outputRecursion( );
}
}
It's a work in progress, but I haven't got to run it and check the logic because I still have two compilation errors in the lines:
listEven.add( in.nextDouble() );
Iterator<Double> it = listEven.iterator();
These two lines throw "cannot find symbol", and I know this is because the ArrayList was declared in a way that makes in inaccessible from methods outside main. I have a rough understanding of the ways of fixing this. I know about setters and getters and they look simple enough from what I researched, but I consider those the last resource since I'm trying to avoid the use of variables (I am aware that my program has other mutable stuff; I'm working on it) in order to meet the restrictions of the exercise as much a possible. I also know that I can make it public static, but then that causes like 15 more errors to appear, and from what I looked up it requires to be "initialized" and it also involves variables.
Are there any other ways to make the ArrayList accessible from those two methods? I'm specially interested in ways that don't involve variables or iteration.
Declare the ArrayList as static but outside of the main function like below:
static ArrayList<Double> listEven = new ArrayList<Double>();
public static void main( String args[ ] )
{
inputRecursion( );
outputRecursion( );
}
public static void inputRecursion( )
{
Scanner in = new Scanner( System.in );
if( in.hasNextDouble() )
{
if( (in.nextDouble() % 2) == 0 )
{
listEven.add( in.nextDouble() );
}
inputRecursion( );
}
}
public static void outputRecursion( )
{
Iterator<Double> it = listEven.iterator();
if( it.hasNext() )
{
System.out.println( it.next() );
outputRecursion( );
}
}
So I'm working on a project for my online AP Computer Science class and have run into a problem... Here's the original class definition I was given to build upon (stripped of code irrelevant to my question):
Note: The constructor of the Bin class accepts a single argument, a String. The String is representative of the Bin's name.
import java.util.*;
public class Warehouse
{
// Declare instance variables here
public Warehouse( int binMax )
{
myBinMax = binMax;
myCatalog = new ArrayList<MusicMedia>();
myBins = new ArrayList<Bin>( 5 );
// Code that will start the warehouse
// off with 5 empty bins
}
public void addBin()
{
myBins.add( new Bin( "B" + myBins.size() ) );
}
}
My job is to replace the areas commented out with actual code implementation. While the declaration of the instance variables is very straight forward, I'm rather torn on the best way to implement the code mentioned in the second comment.
In short, which is the best way to complete the above constructor?
Solution A:
private int myBinMax;
private ArrayList<MusicMedia> myCatalog;
private ArrayList<Bin> myBins;
public Warehouse( int binMax )
{
myBinMax = binMax;
myCatalog = new ArrayList<MusicMedia>();
myBins = new ArrayList<Bin>( 5 );
for(int i = 0; i < 5; i++)
{
myBins.add( new Bin( "B" + myBins.size() ) );
}
}
Solution B:
private int myBinMax;
private ArrayList<MusicMedia> myCatalog;
private ArrayList<Bin> myBins;
public Warehouse( int binMax )
{
myBinMax = binMax;
myCatalog = new ArrayList<MusicMedia>();
myBins = new ArrayList<Bin>( 5 );
for(int i = 0; i < 5; i++)
{
addBin(); // <= Is this considered bad practice?
}
}
Solution C:
// Some magical wizard code I would have never thought of. XD
Thanks in advance!
Can you use Java 8?
final List<Bin> bins = IntStream.range(0, 5).
mapToObj(i -> new Bin("Bin" + i)).
collect(Collectors.toCollection(ArrayList::new));
Otherwise, both your solutions looks fine. I would prefer B as you already have an addBin method with one caveat. You must make addBin final as it is a public method. You should only call private or final methods from constructors otherwise you risk someone (possibly you) overriding that method in a subclass and then the subclasses method will be called from the superclass constructor before the subclass is initialized.
try to use a constant than magic numbers in code :)
import java.util.*;
public class Warehouse
{
// Declare instance variables here
private static final int INITIAL_BINS = 5;
private static final String DEFAULT_BINNAME = "DefaultBin_";
public Warehouse( int binMax )
{
myBinMax = binMax;
myCatalog = new ArrayList<MusicMedia>();
myBins = new ArrayList<Bin>( INITIAL_BINS );
for(int i = 0; i < INITIAL_BINS; i++)
{
myBins.add( new Bin( DEFAULT_BINNAME + i ) );
//addBin();// This is fine too depends on how flexible you want naming to be:)
}
}
public void addBin()
{
myBins.add( new Bin( "B" + myBins.size() ) );
}
}
While I agree with most everything that's already been said, the java 8 functional programming style one-liner is pretty sexy. Magic numbers / strings should be avoided. If your class hasn't gone over functional style why not move the entire for loop into its own function? Generally the only thing that a constructor should do is initialize the state of your object. To make that explicit I try to keep to one line per member variable and that one line is nothing more than an initialization statement. IMO methods (which can reference the current state of the object) shouldn't be called from a constructor because your object hasn't been created yet. If you want to add functions to help you initialize your object, feel free to do so but keep them static so that the intent of the function (not referring to the state of the object) is clear.
...
private static final int INITIAL_BIN_COUNT = 5;
private static final String BIN_PREFIX = "B";
private final List<Bin> myBins;
public Warehouse(...) {
....
myBins = initMyBins();
}
private static List<Bin> initMyBins() {
final List<Bin> result = new ArrayList<Bin>(INITIAL_BIN_COUNT);
for(int i = 0; i < INITIAL_BIN_COUNT; i++) {
result.add(new Bin(BIN_PREFIX+i));
}
return result;
}
...
P.S. A few other notes, it's generally good practice to code to interface types rather than concrete class types (maybe you haven't covered interfaces yet, but that's what I did changing ArrayList to List.
NOTE: I have looked at the other posts, but I'm still quite lost.
This is the code for a private variable that I have in one class:
private int readFile( String fileName)
{
try
{
File f = new File( fileName );
Scanner input = new Scanner( f );
while( input.hasNextLine( ) )
{
String s = input.nextLine( );
String[ ] sArr = s.split( " " );
String animal = sArr[ 0 ];
double cost = Double.parseDouble(sArr [ 1 ] );
boolean penNeeded = Boolean.parseBoolean( sArr[ 2 ] );
boolean available = Boolean.parseBoolean( sArr[ 3 ] );
Pet p = new Pet( animal, cost, penNeeded, available );
if (count < animalList.length )
{
animalList[count] = p;
count++;
}
}
input.close( );
}
catch( Exception e )
{
System.out.println("Error reading the file:");
System.out.println( e );
e.printStackTrace( );
}
return count;
}
I need to access it in this piece of code located in another class:
static public void processTransaction( String fileName, PettingZoo pz )
{
try
{
// variable should be accessed here
}
catch( Exception e )
{
System.out.println("Error reading the file:");
System.out.println( e );
e.printStackTrace( );
}
}
How can I do this? I think that I need to use a modifier of some sort, but I don't know how which one or how to implement it.
You cannot directly access private variables from another class. That's the whole point of declaring it private. What you need to do is use setter and getter methods in class A, then call the get method from class B.
If you want access to a private variable, you can use getter and setter methods.
Example:
private int variable = 5; //<--- your private variable of class A
// a public method (into the same class A)
// that allows the sharing of your private variable
public int getVariable() {
return variable;
}
Now you can call the method getVariable() from an other class (B) and take the value of the private variable (of class A).
As per your comment you can access the private int readFile(String fileName) method by changing the modified of the method. Change the modifier of the method to public or protected. Also since the accessing method is static you need to change the method as static.
So change it as
public static int readFile( String fileName)
{
}
In the processTransaction method invoke it as,
ClassName.readFile("file_name.extn");
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.