How can I convert from a value to an enum? - java

I have an enum that looks a little bit like this:
public enum Numbers {
ONE(1), TWO(2), THREE(3);
public final int num;
public Numbers(int num) {
this.num = num;
}
}
I want to be able to convert from argument to enum, for instance from the int 1 to the enum ONE. Is there any built-in mechanism in Java Enums to do this, or do I have to write my own logic for it?

Yes you have to write your own logic as the num variable is a part of your own logic :
public enum Numbers {
ONE(1), TWO(2), THREE(3);
public final int num;
private Numbers(int num) {
this.num = num;
}
public static Numbers getNumber(int i){
for(Numbers number : Numbers.values()){
if(i == number.num){
return number;
}
}
throw new IllegalArgumentException("This number doesn't exist");
}
}

If you want conversion from the ordinal you have to do it yourself. There is however automatic conversion from the name of an enum. Btw there is no need to specify the ordinal, that is done automatically and it starts with 0 and there is a ordinal() getter.
Enum.valueOf(Numbers.class, "ONE")
would return Numbers.ONE

If you can start your particular enum with ZERO instead, you could do
// ...
private static final Numbers[] list = values();
public static Numbers get(int which) { return list[i]; }
// ...
and ignore assigning indices to your enum.
EDIT: refactor safe option:
//..
private static final Map<Integer, Numbers> getter; static {
Numbers[] ns = values();
getter = new HashMap<Integer, Numbers>(ns.length, 1f);
for (Numbers n : ns) getter.put(n.num, n);
}
public static Numbers get(int which) { return getter.get(which); }
//..
this is also conducive to changing your index to whatever type you like and returns null instead of throwing an exception if you ask for garbage (which can be preferable).

Related

Java: How to externally init an Enum without IF/SWITCH

I have an Enum and I like to use it as a mapping between a symbolical name (NORMAL, SPICY, HOT) and its associated values (11, 22, 33).
Lets say the program should use the symbols and in the database are the values stored.
public static enum MyEnum
{
NORMAL (11),
SPICY (22),
HOT (33);
private int n;
MyEnum (int n) // must be a private constructor because of Java
{
this.n = n;
}
public static void initFromNumber (int n)
{
// ??? how to do that
}
public int get ()
{
return this.n;
}
};
Now I read from the database and try to create/init the Enum.
How can I do that with an Enum (it is clear to me to do it with a class) and without having a big IF or SWITCH in it? Is there an "elegant" way?
Normally in my applications, I will loop over all of the values and find the matching one.
public static MyEnum getByNumber(int n) {
for (final MyEnum value : values()) {
if (value.n == n) {
return value;
}
}
throw new IllegalArgumentException("No MyEnum found for n: " + n);
}
Enum is a singleton and you can not just initialize it. Most probably you want to get enum value by number. You can do this with stream:
public static void initFromNumber (int n)
MyEnum enumValue = Arrays.stream(MyEnum.values())
.filter(myEnum -> myEnum.get() == n)
.findFirst().orElseThrow();
}

Return an array and a variable together in main function

I have a function like that
Class Return_two{
public static void main(String args[]){
int b=0;// Declare a variable
int a []= new int[3];// Declare an array [both are return at the end of the user define function fun()]
Return_two r=new Return_two();
int result_store= r.fun(a,b);//where should I store the result meaning is it a normal variable or an array where I store the result?
}
public int [] fun (int[] array,int var)//may be this is not a good Return type to returning an array with a variable so what will be change in return type?
{
for(int counter=0;counter <array.length;counter++)
{ var=var+counter;
}
return( array,var);// Here how could I return this two value in main function?
}
}
Now, here lies my question. I want to return an array with a variable as I written above.But as I know one can return a array or a variable but not both. Or one can return one or more variable make those variable as a array element. But how can one return an array with an variable in main function?
If you want to create multiple values, wrap them in an object.
(I'm not able to come up with a meaningful name from what you have posted)
class Result {
private int[] a;
private int b;
public Result(int[] a, int b) {
this.a = a;
this.b = b;
}
//Getters for the instance variables
public int[] getA() {
return a;
}
public int getB() {
return b;
}
}
At the end of fun
return new Result(array, var);
Some best practices:
Don't declare variable names with same name as a parameter (a in fun)
In the above Result class, better to create copies on the array a to avoid mutations outside the class.
If possible, don't use arrays and use a List (this would give you a lot of flexibility)
EDIT:
Your caller will look like
Return_two r=new Return_two();
Result result = r.fun(a, b);
result.getA();//Do whatever you want to do with the array
result.getB();//Do whatever you want to do with that variable
With your current version of the (modified) code, why do you want to return the array since it is same as what you pass to the fun method? Returning only the computed var will work for you (and hence the return type can simply be int).
You can also achieve what you do in fun in one line
return (array.length * (array.length - 1)) / 2;
Wrap these properties into a object, say
Public class FunModel
{
public int[] a;
public int b;
}
then you can return an instance of `FunModel`.
Or
you can use `Tuples`
------------------
Futher Explanation
------------------
The return type here should be a model.
This model should have all that you want to return as properties.
You can return this model from your method.
public class FunModel
{
public int[] a;
public int b;
public FunModel(int[] a, int b) {
this.a = a;
this.b = b;
}
}
And the method should return a instance of this model.
public class ReturnTwo {
public static void main(String args[]){
int b=0;
int a []= new int[3];
ReturnTwo returnTwo = new ReturnTwo();
FunModel funModel = returnTwo.fun(a,b);
//other processing
}
public FunModel fun (int[] array,int tempVar)
{
FunModel temp = new FunModel(array,tempVar);
for(int counter=0;counter <array.length;counter++)
{
temp.b = temp.b + counter;
}
return temp;// you return the model with different properties
}
}

When creating new objects, my counter stays the same number

I working on a program where I need to count the how many objects are created by a certain class (and all its sub-classes). I made a quick test program that replicated my problem:
public class Test {
private int number = 0;
public Test(){
number++;
}
public int returnNumber(){
return number;
}
}
How do I make the variable 'number' save its value, instead of initializing every time I create a new object?
Make number static in order for it to have the same value for all instances of your class.
private static int number = 0
You might want to change your returnNumber to be static too.
If you want each instance of your class to have a unique number, you should keep that number in a separate member :
public class Test {
private int number = 0;
private static int counter = 0;
public Test(){
number = counter++;
}
public int getNumber() {
return number; // each instance will have a unique value
}
public static int getCounter () {
return counter; // this will return the current value of the counter
}
}
number needs to be a static type so its shared across all instances of your class.
Consider private static int number = 0 instead.
Better still, you ought to make number an atomic type, so multiple constructors can be called on several threads. (Otherwise you could end up underestimating number.)
Consider using AtomicInteger as the type; still static of course.
create variable as static
private static int number = 0;
Make it
private static int number = 0;
public class Test {
private static int number = 0;
public Test(){
number++;
}
public int returnNumber(){
return number;
}
}

Method cannot modify input int parameter

Not to sure why the integers lowRange and highRange are not going between these classes.
package guessnumber;
public class GuessNumber
{
static public int computerGenedNumber;
static public int lowRange;
static public int highRange;
static public int playerGuess;
public static void main(String[] args)
{
Input.range(lowRange, highRange);
Rand.number(lowRange, highRange, computerGenedNumber);
Input.guess();
Give.result();
}
}
Next Class:
package guessnumber;
import javax.swing.JOptionPane;
class Input
{
public static void range(int lowRange, int highRange)
{
String rawUserInput;
rawUserInput = JOptionPane.showInputDialog("Please enter the range you wish to guess. (EX: 1-10)", "1-10");
for(int i = 0; i < rawUserInput.length(); i++)
{
if(rawUserInput.charAt(i) == '-')
{
lowRange = Integer.parseInt(rawUserInput.substring(0, i));
highRange = Integer.parseInt(rawUserInput.substring(i + 1, rawUserInput.length()));
}
}
}
static void guess()
{
}
}
And the last relevant one:
package guessnumber;
class Rand
{
static public void number(int lowRange, int highRange, int computerGenedNumber)
{
computerGenedNumber = (int)(Math.random() * (highRange - lowRange) + lowRange);
}
}
The rest of the classes are currently blank so I don't think I need to put them here too.
Here is a simplified piece of code which reproduce your problem, and make sure you understand why it is causing problem and the solution:
class Foo {
public static void square(int a, int result) {
result = a*a;
}
}
class Bar {
public static void main(String[] args) {
int a=2;
int result = 0;
Foo.square(a, result);
System.out.println("result " + result);
}
}
This should be fundamental understanding of Java. Checkout what is the meaning of "pass-by-value"
In brief, the parameter passed in the method is a copy of the argument. Therefore when you are changing the parameter in your method, you are just changing another piece of data, and your change is not reflected to caller.
One way to fix is to change the method and return your result, which looks like:
class Foo {
public static int square(int a) {
return a*a;
}
}
class Bar {
public static void main(String[] args) {
int a=2;
int result = 0;
result = Foo.square(a);
System.out.println("result " + result);
}
}
Another common solution is to pass in a "holder object" as the result. Although the object reference is passed by value, that copy of object reference is still pointing to the same object as caller. I won't go too deep into this as it is less common and you should be able to get the proper way doing so once you have better understanding on how value (including object reference) is passed around.
Parameters are passed "by value" in Java. What that means is that when you call
input.range(lowRange, highRange);
it gives the current values of those variables to input.range, but it doesn't give input.range a way to modify them. In the range method:
public static void range(int lowRange, int highRange)
the parameters lowRange and highRange (which have no connection with the variables in GuessNumber, even though the names are the same) are copies of what you pass in. When you assign lowRange = ... in the method, it changes the copy but has no effect at all on the lowRange and highRange in GuessNumber.
You need to write a range method that returns two values. This needs a little bit of work, but I'd write a Range class that has low and high members, and then change your method to
public static Range range()
That method would have to create a new Range object. I think it's OK for low and high to be public members of Range:
class Range {
public int low;
public int high;
public Range(int low, int high) {
this.low = low;
this.high = high;
}
}
Normally, public data in a class is a bad thing, but for a class whose only purpose is to let a method return multiple values, it's OK in my opinion.

Java: How to define custom Integer-based data type?

I need a data type that behaves completely like Integer with this difference that I want it to overflow and underflow to certain values. On the other words, I'd like to set the MAX_VALUE and MIN_VALUE of an object/instance of the Integer class. The problem is MAX_VALUE and MIN_VALUE are constant and Integer class in final. How should I approach?
You'll have to create your own wrapper class:
public class CustomInteger
{
public static final int MAX_VALUE = 5000;
public static final int MIN_VALUE = -5000;
private final int value;
public CustomInteger(int value)
{
// TODO: Validation
this.value = value;
}
// Add all the methods you want - e.g. integer operations etc
// performing custom overflow/underflow on each operation
}
You need to decide whether you want one fixed pair of limits for the whole type, or whether each instance can have a different limit (and what that means when adding together two values with different limits etc).
Since java.lang.Integer is final you cannot extend it. The only choice is to wrap it:
public class LimitedInteger {
private int value;
private int min;
private int max;
LimitedInteger() {
}
LimitedInteger(int value) {
this.value = value;
}
LimitedInteger(int value, int min, int max) {
this.value = value;
this.min = min;
this.max = max;
}
}
etc, etc

Categories

Resources