Decrease and Increase Enum value [duplicate] - java

This question already has answers here:
What's the best way to implement `next` and `previous` on an enum type?
(7 answers)
Closed 6 years ago.
I would like to create a method called increaseValue, which it's signature is as following:
public Size increaseValue(Size s)
Also I have the following statement:
protected enum Size {XS, S, M, L, XL}
I need to know, how can I make the method return correct value (i.e. XL when input is L... etc.) while not using Switch-Case statement ?
Thanks !

You could assume they are in increasing ordinal() order. I would add this a method on Size.
protected enum Size {
XS, S, M, L, XL;
static final Size[] VALUES = values();
public Size incrementSize() { return VALUES[ordinal()+1]; }
public Size decrementSize() { return VALUES[ordinal()-1]; }
}
Note: I wouldn't assume that XS is after XL, but rather you get an error (though not a very clear one)
Note: every time you call values() it creates a new array. It has to do this because the array is mutable and you might change it. I highly recommend saving a copy and avoid calling values() each time.
You can make the error messages clearer by overriding those methods.
protected enum Size {
XS {
public Size decrementSize() { throw new UnsupportedOperationException("No smaller size"); }
},
S,
M,
L,
XL {
public Size incrementSize() { throw new UnsupportedOperationException("No larger size"); }
};
static final Size[] VALUES = values();
public Size incrementSize() { return VALUES[ordinal()+1]; }
public Size decrementSize() { return VALUES[ordinal()-1]; }
}

Here's why you should not do it: if you perform arithmetic on your enum, you can end up with invalid values, for instance what would happen if you added one to XL?
Here's how you do it:
Size.values()[s.ordinal()+1]

In good OO design you want to internalize such things. Meaning: you want to provide a method like "nextSize()" within that enum, like:
public enum Size {
XS, ...;
public Size nextSize() {
switch (this) ...
In this situation, the values are probably "fixed"; but in other situations, you might later want to insert new constants; thus I prefer an explicit mapping here; instead of relying on calls to ordinal().
And as mentioned in the other answers: you need to define what largestSize().nextSize() means. It could throw an exception, or return null (baaad idea). Alternatively, that method could return Optional<Size>; to make it clear to the caller that this method doesn't always return a valid result.

public Size increaseValue(Size s) {
Size[] allValues = Size.values();
var newOrdinal = s.ordinal() + 1;
return (newOrdinal >= allValues.length) ? null) : allValues[newOrdinal];
}
public Size decreaseValue(Size s) {
var newOrdinal = s.ordinal() - 1;
return (newOrdinal < 0) ? null : values()[newOrdinal];
}

You van modify this enum like this:
protected enum Size {
XS,(1)
S(2),
M(3),
L(4),
XL(5);
private int sizeNo;
Size(int sizeNo) {this.sizeNo = sizeNo;}
Size getBySizeNo(int sizeNo){
for(size : Size.values()) {
if (sizeNo == size.getSizeNo() ) {
return size;
}
}
throw new IllegalArgumentException() ;
}
public Size increaseValue(Size s){
return getBySizeNo(s.getSizeNo() +1) ;
}
}

Try this:
public Size increaseValue(Size s) {
return Size.values()[s.ordinal() + 1]
}

Related

How to count the nested list elements size using Java 7?

I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}

Modifying local variable from inside lambda

Modifying a local variable in forEach gives a compile error:
Normal
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
With Lambda
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
Any idea how to resolve this?
Use a wrapper
Any kind of wrapper is good.
With Java 10+, use this construct as it's very easy to setup:
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
With Java 8+, use either an AtomicInteger:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
... or an array:
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
Note: be very careful if you use a parallel stream. You might not end up with the expected result. Other solutions like Stuart's might be more adapted for those cases.
For types other than int
Of course, this is still valid for types other than int.
For instance, with Java 10+:
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
Or if you're stuck with Java 8 or 9, use the same kind of construct as we did above, but with an AtomicReference...
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
... or an array:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
This is fairly close to an XY problem. That is, the question being asked is essentially how to mutate a captured local variable from a lambda. But the actual task at hand is how to number the elements of a list.
In my experience, upward of 80% of the time there is a question of how to mutate a captured local from within a lambda, there's a better way to proceed. Usually this involves reduction, but in this case the technique of running a stream over the list indexes applies well:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
If you only need to pass the value from the outside into the lambda, and not get it out, you can do it with a regular anonymous class instead of a lambda:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
As the used variables from outside the lamda have to be (implicitly) final, you have to use something like AtomicInteger or write your own data structure.
See
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables.
An alternative to AtomicInteger is to use an array (or any other object able to store a value):
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
But see the Stuart's answer: there might be a better way to deal with your case.
Yes, you can modify local variables from inside lambdas (in the way shown by the other answers), but you should not do it. Lambdas have been made for functional style of programming and this means: No side effects. What you want to do is considered bad style. It is also dangerous in case of parallel streams.
You should either find a solution without side effects or use a traditional for loop.
If you are on Java 10, you can use var for that:
var ordinal = new Object() { int value; };
list.forEach(s -> {
s.setOrdinal(ordinal.value);
ordinal.value++;
});
You can wrap it up to workaround the compiler but please remember that side effects in lambdas are discouraged.
To quote the javadoc
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement
A small number of stream operations, such as forEach() and peek(), can operate only via side-effects; these should be used with care
I had a slightly different problem. Instead of incrementing a local variable in the forEach, I needed to assign an object to the local variable.
I solved this by defining a private inner domain class that wraps both the list I want to iterate over (countryList) and the output I hope to get from that list (foundCountry). Then using Java 8 "forEach", I iterate over the list field, and when the object I want is found, I assign that object to the output field. So this assigns a value to a field of the local variable, not changing the local variable itself. I believe that since the local variable itself is not changed, the compiler doesn't complain. I can then use the value that I captured in the output field, outside of the list.
Domain Object:
public class Country {
private int id;
private String countryName;
public Country(int id, String countryName){
this.id = id;
this.countryName = countryName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Wrapper object:
private class CountryFound{
private final List<Country> countryList;
private Country foundCountry;
public CountryFound(List<Country> countryList, Country foundCountry){
this.countryList = countryList;
this.foundCountry = foundCountry;
}
public List<Country> getCountryList() {
return countryList;
}
public void setCountryList(List<Country> countryList) {
this.countryList = countryList;
}
public Country getFoundCountry() {
return foundCountry;
}
public void setFoundCountry(Country foundCountry) {
this.foundCountry = foundCountry;
}
}
Iterate operation:
int id = 5;
CountryFound countryFound = new CountryFound(countryList, null);
countryFound.getCountryList().forEach(c -> {
if(c.getId() == id){
countryFound.setFoundCountry(c);
}
});
System.out.println("Country found: " + countryFound.getFoundCountry().getCountryName());
You could remove the wrapper class method "setCountryList()" and make the field "countryList" final, but I did not get compilation errors leaving these details as-is.
To have a more general solution, you can write a generic Wrapper class:
public static class Wrapper<T> {
public T obj;
public Wrapper(T obj) { this.obj = obj; }
}
...
Wrapper<Integer> w = new Wrapper<>(0);
this.forEach(s -> {
s.setOrdinal(w.obj);
w.obj++;
});
(this is a variant of the solution given by Almir Campos).
In the specific case this is not a good solution, as Integer is worse than int for your purpose, anyway this solution is more general I think.

How to use ENUM to return random strings out of three?

With the use of below code, I am finding out which datacenter I am in and it is working fine..
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
private static DatacenterEnum compareLocation() {
String ourhost = getHostName();
for (DatacenterEnum dc : values()) {
String namepart = "." + dc.name().toLowerCase() + ".";
if (ourhost.indexOf(namepart) >= 0) {
return dc;
}
}
return null;// I don't want to do this now.
}
}
But it might be possible that it is not able to find any datacenter, so currently I am returning null.
Is there any direct way or a single line command by which I can return randomly either DC1 or DC2 or DC3 in the ENUM instead of returning null?
I know one way is to make a list of string and then randomnly select any integer between 0 to 2 inclusive and then find the string. But it is too much code, actually it's not but just trying to see is there any other way we can do this?
Any simple and direct way which I can use in the ENUM directly?
Here's the one line:
return DataCenterEnum.values()[new Random().nextInt(3) + 1)];
For those who require tighter control on their code, here's a safer version, which does not depend on the order of the enum instances:
return new DataCenterEnum[]{DC1, DC2, DC3}[new Random().nextInt(3)];
Here is a generic solution that will work for any enumeration.
Convenience method for single exclusion:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, E exclude) {
return getRandom(aEnum, Collections.singletonList(exclude));
}
Generic method that works with one or more exclusions:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, List<E> exclude){
//Convert set of enums into a list
List<E> enums = new ArrayList<E>(EnumSet.allOf(aEnum));
//Remove items from the list that you want to exclude
enums.removeAll(exclude);
int size = enums.size();
if(size != 0){
//Get random enum
int randomIndex = new Random().nextInt(size);
return enums.get(randomIndex);
} else {
throw new IllegalArgumentException("Empty Enumeration after excludes");
}
}
For your example you could call
EnumUtil.getRandom(DatacenterEnum.class, DatacenterEnum.DEV);
You could use the values() method, which returns an array. Then just use Math.random() to return a random instance.
Here is an example:
public static void main (String[] args) {
String[] arr = {"DEV","DC1","DC2","DC3"}; //returned by Enum.values(), you get the idea
String randElement = arr[(int) ((Math.random() * 3) +1)];
System.out.println(randElement);
}
Basically it boils down to generating a random number between 1 and n :)

How to use writeStringArray() and readStringArray() in a Parcel

I recently came across a very stupid (at least from my point of view) implementation inside Androids Parcel class.
Suppose I have a simple class like this
class Foo implements Parcelable{
private String[] bars;
//other members
public in describeContents(){
return 0;
}
public void writeToParcel(Parcel dest, int flags){
dest.writeStringArray(bars);
//parcel others
}
private Foo(Parcel source){
source.readStringArray(bars);
//unparcel other members
}
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>(){
public Foo createFromParcel(Parcel source){
return new Foo(source);
}
public Foo[] newArray(int size){
return new Foo[size];
}
};
}
Now, if I want to Parcel a Foo Object and bars is null I see no way to recover from this situation (exept of catching Exceptions of course). Here is the implementation of these two methods from Parcel:
public final void writeStringArray(String[] val) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i<N; i++) {
writeString(val[i]);
}
} else {
writeInt(-1);
}
}
public final void readStringArray(String[] val) {
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
val[i] = readString();
}
} else {
throw new RuntimeException("bad array lengths");
}
}
So writeStringArray is fine if I pass bars which are null. It just writes -1 to the Parcel. But How is the method readStringArray supposed to get used? If I pass bars inside (which of course is null) I will get a NullPointerException from val.length. If I create bars before like say bars = new String[???] I don't get any clue how big it should be. If the size doesn't match what was written inside I recieve a RuntimeException.
Why is readStringArray not aware of a result of -1 which gets written on null objects from writeStringArray and just returns?
The only way I see is to save the size of bars before I call writeStringArray(String[]) which makes this method kind of useless. It will also redundatly save the size of the Array twice (one time for me to remember, the second time from writeStringArray).
Does anyone know how these two methods are supposed to be used, as there is NO java-doc for them on top?
You should use Parcel.createStringArray() in your case.
I can't imagine a proper use-case for Parcel.readStringArray(String[] val) but in order to use it you have to know the exact size of array and manually allocate it.
It's not really clear from the (lack of) documentation but readStringArray() is to be used when the object already knows how to create the string array before calling this function; for example when it's statistically instanciated or it's size is known from another previously read value.
What you need here is to call the function createStringArray() instead.

Optional class-members

I import data from a XML file to use it internally. Now there is an uint value, which is (according to the XSD) not required. Now here is the question: How do map this behaviour in my class (it is unclear, if the Value is present or not, but I need to know at runtime)
Basically I see 3 solutions:
Solution 1: Use values of which we know that they are invalid to flag the Value as 'not-set':
public class Solution1 {
private int optionalVal;
public boolean isSetOptionalVal() {
return (optionalVal>=0);
}
public void setOptionalVal(int val) {
optionalVal = val;
}
public void unSetOptionalVal() {
optionalVal = -1;
}
public int optionalVal() {
if(isSetOptionalVal()) {
return optionalVal;
} else {
return -1;
}
}
}
Solution 2: Use the boxed class and set it to null if the value is 'not-set':
public class Solution2 {
private Integer optionalVal;
public boolean isSetOptionalVal() {
return (optionalVal!=null);
}
public void setOptionalVal(int val) {
optionalVal = val;
}
public void unSetOptionalVal() {
optionalVal = null;
}
public int optionalVal() {
if(isSetOptionalVal()) {
return optionalVal;
} else {
return -1;
}
}
}
Solution 3: Use an additional variable that describes the value as 'not-set':
public class Solution3 {
private int optionalVal;
private boolean optionalValSet;
public boolean isSetOptionalVal() {
return (optionalValSet);
}
public void setOptionalVal(int val) {
optionalVal = val;
optionalValSet = true;
}
public void unSetOptionalVal() {
optionalValSet = false;
}
public int optionalVal() {
if(isSetOptionalVal()) {
return optionalVal;
} else {
return -1;
}
}
}
These are my proposals to solve the issue, but I don't really like any of those.
Solution 1 seems very hacky, maybe there is somewhere a point where I can't determine the invalid value.
Solution 2 is actually the solution I am using, but I only need the additional information for some of the memeber variables, so I have either to use some variables as boxed types and some as primitive (which seems inconsistent) or I have always to use the boxed types (which I don't really like).
Solution 3 seems to be the cleanest, but here I am worried, that at some place the bool isn't set correctly, which would be a hard to find error (I already have a lot of code, and found the problem, that some elements are not set in the XML just recently)
So...what would you prefer as a solution to solve the "Optional Value"-problem - is there maybe an even better solution?
How is this problem generally handled?
I'd choose option 2, using the Integer class, and leave the conversion between int and Integer to autoboxing. The advantage of this approach is that it keeps everything concerned with your optional value in a single variable.
The first option is a magic value, and if the unused value becomes a used value later, it becomes a nightmare to maintain.
The third option means having to keep track of both the int and the boolean that keeps track of the question whether it is used. If you're going to do this, consider making it a class in and of itself... but then you might as well use Integer.
Solution 2 is by far the cleanest. That's exactly what null is for, and using primitive types for some values and wrapper types for others communicates that there's a difference - theres nothing inconsistent about it.
I'd also prefer solution 2, which is what we generally use as well.
Just a note though: your getters/setters should reflect that, i.e. they should look like this (which might actually be the case in your code but not in your post):
public void setOptionalVal(Integer val) {
optionalVal = val;
}
public Integer optionalVal() {
return optionalVal;
}
Since you already have null as the indicator whether the optional value is set or not, I'd not introduce another value (-1 in your case). If you need a default value that's most likely dependent on the user of that object.

Categories

Resources