Java Optional<T> questions, am I doing this right? - java

I've had a "Bad habit" of tossing null into places, such as enumerators when something doesn't exist.
Example:
private enum Foo {
NULL(1, null, 2),
NOT_NULL(3, new Bar(), 4);
private int a, c;
private Bar b;
Foo(int a, Bar b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
So now I'm trying to convert my code to use Optional<T> Like everyone is suggesting, but I'm not sure if I'm doing it correctly.
Here's my code (Trimmed enum):
public static enum Difficulty {
EASY, MEDIUM, HARD
}
public static enum SlayerTasks {
NONE(0, Optional.empty(), Optional.empty(), Optional.empty()),
NPC(1, Optional.of(Difficulty.EASY), Optional.of("That one place."), Optional.of(1));
private int taskId;
private Optional<Difficulty> difficulty;
private Optional<String> location;
private Optional<Integer> npcId;
SlayerTasks(int taskId, Optional<Difficulty> difficulty, Optional<String> location, Optional<Integer> npcId) {
this.taskId = taskId;
this.difficulty = difficulty;
this.location = location;
this.npcId = npcId;
}
public int getTaskId() {
return taskId;
}
public Difficulty getDifficulty() {
return difficulty.get();
}
public String getLocation() {
return location.get();
}
public int getNpcId() {
return npcId.get();
}
}
What's bothering me is the documentation referring to #get() found here where it states:
If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.
So, I figured that in order to prevent this I would wrap the getter in #isPresent(), but then I couldn't figure out how to return empty.
Is this the correct way to do things, or am I missing something? I'm not looking for a "Fix", I'm looking for information on efficiency and proper practices.

You need to ask yourself what you want your getter to do if there's nothing to return.
There are only really four options:
Return a null (but then you're back to what you were trying to avoid);
Have your getter return an Optional<T> instead of a T;
Return a default value if there's nothing set;
Throw an exception.
I'd go with 2 unless there's a very clearly right answer for what the default should be. 4 is appropriate only if the client code should always know whether there's something there and only ask for it if there is (which would be unusual, though not impossible).

You can replace location.get() with location.orElse("SomeDefaultValue") if you wish to avoid the exception. This allows you to return a default value when the Optional is empty.

IMO, if you're implementing your logic using 'maybe' monad (Optional values) you should stick to Optional object and toss it around, extracting the wrapped value only if its required.
To modify undelying value you can use Optional.ifPresent(), Optional.map() or Optional.flatMap() methods, e.g.
Optional<Difficulty> difficulty = NPC.getDifficulty();
difficulty.ifPresent(diff -> { /* do comething here ... */ });

Related

Proper Constructors to Run all Methods in Java

I have this class and need to know which constructor is needed to create an object that may immediately use all its methods without error
public class Robot {
private boolean fuelEmpty = true;
private int roboID;
private String greeting;
private String securityProtocol;
//insert robot constructor here
public void destroyAllHumans(){
while (fuelEmpty == false) {
//robot begins to destroy all humans
}
}
public int getRoboID(){
return roboID;
}
public void greet(){
System.out.println(greeting);
}
public void setSecurityProtocol(String proto){
securityProtocol = proto;
}
}
For example should look like this:
public Robot(int id, String greet) {
roboID = id;
greeting = greet;
}
or this:
public Robot(int id, String greet) {
roboID = id;
greeting = greet;
fuelEmpty = false;
}
or:
public Robot(boolean full, int id, String greet, String proto) {
roboID = id;
greeting = greet;
fuelEmpty = full;
securityProtocol = proto;
}
Which of these (or something else different) is needed so that all the other methods can run without an error?
You can overload the constructor as much as you need, the important thing is
the object gets properly instantiated after you create a new one...
a way can be:
public Robot() {
this(false, 0, "", "");
}
public Robot(int id) {
this(false, id, "", "");
}
public Robot(boolean fuelEmpty, int roboID, String greeting, String securityProtocol) {
this.fuelEmpty = fuelEmpty;
this.roboID = roboID;
this.greeting = greeting;
this.securityProtocol = securityProtocol;
}
so look how all other constructors will at the end call internally the
public Robot(boolean fuelEmpty, int roboID, String greeting, String securityProtocol)
that will give you the waranty that no matter which constructor is invoked, the Robot is fully created and can invoke all those methods without crashing
The solution works like this:
you look at each of your methods
you check which fields each method is using
you check more closely, if the method breaks when that field has its default value (like null for Objects, or false for booleans)
When you do that for all methods, you get a list of those fields that you need to initialize somehow. Then you could go forward and define a corresponding constructor.
But of course, that is the wrong approach.
The real answer goes like this: you don't put fields into a class because you can. You add them because they are required so that this class can implement the requirements (responsibilities) that you want it to implement. Meaning: you focus on the methods that your class should provide. Then you clarify which fields you need in order to implement these methods.
In other words: you have exactly those fields in your class that your class needs. If you have fields in there that go unused - then you get rid of them.

Can a method return a set of different return types in a succinct way?

How would I get the string Percent from getData? Is there a way to have getData return multiple strings and request only the ones I choose from it, like if I wanted the percentage number I would call getData("http://woot.com").Percentage?
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Wooot {
public static void main(String[] args) throws IOException, InterruptedException {
needData();
Report();
}
public static void Report() throws InterruptedException, IOException{
while (needData() == true)
{
System.out.println(getData("http://woot.com"));
Thread.sleep(5000);
}
}
public static boolean needData(){
return true;
}
public static String getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return name;
}
}
You can make a class to hold the fields you want back:
class SomeData {
private final String percent;
private final String name;
public SomeData(String percent, String name) {
this.percent = percent;
this.name = name;
}
public String getName() {return name;}
public String getPercent() {return percent;}
}
It is a valid point that getters here are not an absolute necessity. Since Java doesn't follow the universal access principle introducing them later can be a little awkward, so I add them in up front. But mostly I do it because my co-workers are used to seeing the getters and I try to avoid weirding them out too much.
You could also add a convenience constructor:
public SomeData(Document document) {
this(doc.select(".percent-remaining").first().text(),
doc.select("h2").first().text());
}
This way retrieving the data fields would be in a different place from the connection logic, so you don't have the SRP violation of having multiple reasons for a class to change.
Using some general purpose collection like a Tuple or Map is an option. Tuples are ugly because the names of the fields get discarded. With maps, if entries have different types then the compile-time type-checking gets lost.
Alternatively you could return the Document object instead. I'm not sure introducing a new data holder class here is better than using Document.
Struct-like object return
There are a few ways you can get "effective" multiple returns. I usually use a lightweight struct-like class to support this
public static String getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return new ImportantData(name,percent) ;
}
class ImportantData{
public final String name;
public final String percent; //not sure why the percentage is a string
public ImportantData(String name, String percent){
this.name=name;
this.percentage=percentage;
}
}
This is one of the rare cases where getters add no value and a final field makes more sense.
Store objects passed as arguments
An alternative I have also seen is to pass a store object to the method. This only works with mutable objects and is far less clear than the Struct-like object return. Make sure to produce clear documentation if using this approach.
public static String getData(String url, Vector3d store) throws IOException {
store.x=1;
store.y=2;
store.z=3;
return "someOtherString" ;
}
You can create a class Data with an attribute Percentage. Something like:
public class Data {
private String percentage;
public Data() {
}
public String getPercentage() {
return percentage;
}
public void setPercentage(String percentage) {
this.percentage = percentage;
}
}
Then, you can call:
Data d = wooot.getData();
String percentage = d.getPercentage();
Without paying attention to what you are trying to accomplish, I think the "general purpose" solution for this problem would be to return an instance of a new class that wrapped both values.
public static class DataResults
{
private final String percent;
private final String name;
public DataResults(String percent, String name) {
super();
this.percent = percent;
this.name = name;
}
public String getPercent() {
return percent;
}
public String getName() {
return name;
}
}
public static DataResults getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return new DataResults(percent, name);
}
When you think you need multiple results from a method, you're really trying to represent something conceptually more complicated than two separate values. You're actually trying to represent two results and the relationship between them. Take, for instance, the idea of integer division, when you care about both the result and the remainder. The first option would be to just define two separate methods, divide(), and mod(). The problem is now a) you do the same operation twice, and b) you separate obviously connected logic. You're not actually trying to return two pieces of data, you're trying to return one, more complicated result.
public class DivMod {
public final int result;
public final int remainder;
// standard constructor, getters aren't strictly necessary in such a simple class
}
public static DivMod divMod(int dividend, int divisor) {
// compute remainder, result
return new DivMod(remainder, result);
}
This snippet hopefully makes it clear that there's often there's something even better you could do - do the computation in the object:
public class DivMod {
private final int dividend, divisor, result, remainder;
public DivMod(int dividend, int divisor) {
this.dividend = dividend;
this.divisor = divisor;
// calculate and set result and remainder
}
// standard getters
}
Now we've really compartmentalized what we're trying to do with proper Object Oriented Programming. There's no need for a static method, and all the logic is clearly in one place. Even better, we avoid the above case where a meaningless DivMod is constructed (one that doesn't actually represent a division result). We guarantee that every DivMod instance is an immutable result of integer division.
There are two standard alternatives to the above, both of which are anti-patterns. The first is to return an array or a Collection, and the second is to define some sort of general Tuple class that holds multiple arbitrary data types. While tuples at least offer the benefit of being a fixed size, and the ability to hold different types in the same object, they are terribly poor alternatives to a proper OOP design. Guava offers some insight in their Idea Graveyard, as well.
See also #RichardTingle's suggestion of passing a mutable object into your method in order to update it with additional data, but consider this strictly a last resort option; it generally introduces far more confusion than benefit.
You can use String[] and return an Array of Strings.

Design Issue | Enum to represent combo box options

I need to use an Enum with a combobox (values shown below).
YES (shown as YES on UI, stored in DB as Y)
NO (shown as NO on UI, stored in DB as N)
DEFAULT (shown as "" on UI, stored in DB as null)
The Enum has methods to perform the following -
toString() - to provide the custom String for UI. (showing the combo options)
OptionToDB (static) - Convert a selected option to db value (on save / update)
DBToOption (static)- Convert a DB value to selcted option (while loading the screen)
static enum EnumOption{
YES,NO,DEFAULT;
....
public static EnumOption DBToOption(String val){
if("Y".equals(val)){
return YES;
} else if("N".equals(val)){
return NO;
}else {
return DEFAULT;
}
}
....
}
It works pretty well, but the issue with above methods is that it uses if/else comparison to deduce which option / db value to be returned.
I thought of storing the dbValue as a field in enum but I was not able to reduce the if/else from DBToOption.
Can this if/else be avoided in any way using a better design??
If you store the dbValue as a field in the enum, you can remove the if/else and replace it with a for-loop, although I don't see anything wrong with those if/elses for this particular case:
static enum EnumOption {
YES("Y"),
NO("N"),
DEFAULT("");
private final String value;
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
for (EnumOption opt : EnumOption.values()) {
if (opt.value.equals(val)) {
return opt;
}
}
return DEFAULT;
}
}
public enum EnumOption {
YES("Y"), NO("N"), DEFAULT("");
private final String value;
private final static Map<String, EnumOption> options;
static {
options = new HashMap<String, EnumOption>();
for (EnumOption opt : EnumOption.values()) {
options.put(opt.value, opt);
}
}
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
return options.get(val) != null ? options.get(val) : DEFAULT;
}
}
And here is the test that proves it works.
public void testDBToOption() {
assertEquals(EnumOption.NO, EnumOption.DBToOption("N"));
assertEquals(EnumOption.YES, EnumOption.DBToOption("Y"));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(""));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(null));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption("R"));
}
So you want to get rid of the remaining if/else ...Are you doing Object Calisthenics?
You could do the following, if you do not have compatibility issues:
public enum EnumOption {
Y("Y", "YES"),
N("N", "NO"),
D("D", "");
private final String dbValue;
private final String uiValue;
private EnumOption(String dbValue, String uiValue) {
this.dbValue = dbValue;
this.uiValue = uiValue;
}
public String getDbValue() {
return this.dbValue;
}
public String uiValue() {
return this.uiValue;
}
public static EnumOption getFromDb(String dbValue) {
return EnumOption.valueOf(dbValue);
}
}
Since each enum value can only occur once, this has at least the same performance as all the other implementations.
For details about the automatically generated valueOf(String) method in enum types, and James DW's solution, you can read up in Josh Bloch's Effective Java Item 30 (Use enums instead of int constants), page 154.

Return enum value without calling get function

Is it possible in Java to return the enum value without having to call a function to return the value, such as getFlag() in my example? If so, how?
public enum MessageFlags {
BIT0((short)1),
BIT1((short)2),
BIT2((short)4),
BIT3((short)8),
BIT4((short)16),
BIT5((short)32),
BIT6((short)64),
BIT7((short)128),
BIT8((short)256),
BIT9((short)512),
BIT10((short)1024),
set_freq(BIT0),
get_freq(BIT1);
short bitFlag = 0;
MessageFlags flag;
MessageFlags(short flag) {
this.bitFlag = flag;
}
MessageFlags(MessageFlags flag) {
this.flag = flag;
}
public short getFlag() {
return this.flag.bitFlag;
}
public short getValue() {
return this.bitFlag;
}
}
Just say MessageFlags.BITX and that will return the same value as getFlag()
You can import static MessageFlags.*; and say BITX.getFlag().
Here is a complete example:
A.java
package foo;
import static foo.B.*;
public class A{
public B value = BAR;
}
B.java
package foo;
public enum B{
BAR, BAZ, BOO
}
I followed #Jeremy's advice of this:
package foo;
import static foo.B.*;
and then I created a method called set_freq in my MessageFlags enum. I made this function static and had it return short. For example,
public static short set_freqflag() {
return BIT0.getFlag();
}
The semantics of set_freqflag are a little weird because you are not setting anything but I do not have a better name at the moment. This allows me to just state set_freqflag() rather than the longer way I was doing before.
I might be really late, but I'm writing to anyone who visits this topic for help.
If you have an enum, and you'd like to return a specific parameter of its values by default without calling a get function, you need to insert an #Override above your selected function, like:
public class Plants {
public enum Fruits {
APPLE ("sweet"),
GRAPEFRUIT ("sour");
private String taste;
Fruits (String taste) {
this.taste = taste;
}
#Override
public String getTaste() {
return this.taste;
}
}
}
And now you can call whichever enum value you'd like, without a get function:
Plants.Fruits.APPLE
And it'll return "sweet"
P.S. I'm not a professional programmer, please correct me if I've written something anti-conventional by accident.

Get enum by its inner field

Have enum with inner fields, kind of map.
Now I need to get enum by its inner field.
Wrote this:
package test;
/**
* Test enum to test enum =)
*/
public enum TestEnum {
ONE(1), TWO(2), THREE(3);
private int number;
TestEnum(int number) {
this.number = number;
}
public TestEnum findByKey(int i) {
TestEnum[] testEnums = TestEnum.values();
for (TestEnum testEnum : testEnums) {
if (testEnum.number == i) {
return testEnum;
}
}
return null;
}
}
But it's not very efficient to look up through all enums each time I need to find appropriate instance.
Is there any other way to do the same?
You can use a static Map<Integer,TestEnum> with a static initializer that populates it with the TestEnum values keyed by their number fields.
Note that findByKey has been made static, and number has also been made final.
import java.util.*;
public enum TestEnum {
ONE(1), TWO(2), SIXTY_NINE(69);
private final int number;
TestEnum(int number) {
this.number = number;
}
private static final Map<Integer,TestEnum> map;
static {
map = new HashMap<Integer,TestEnum>();
for (TestEnum v : TestEnum.values()) {
map.put(v.number, v);
}
}
public static TestEnum findByKey(int i) {
return map.get(i);
}
public static void main(String[] args) {
System.out.println(TestEnum.findByKey(69)); // prints "SIXTY_NINE"
System.out.println(
TestEnum.values() == TestEnum.values()
); // prints "false"
}
}
You can now expect findByKey to be a O(1) operation.
References
JLS 8.7 Static initializers
JLS 8.9 Enums
Related questions
Static initalizer in Java
How to Initialise a static Map in Java
Note on values()
The second println statement in the main method is revealing: values() returns a newly allocated array with every invokation! The original O(N) solution could do a little better by only calling values() once and caching the array, but that solution would still be O(N) on average.
Although someone has suggested using Map<Integer, TestEnum> think twice about it.
Your original solution, especially for small enums, may be magnitudes faster than using HashMap.
HashMap will probably be not faster until your enum contains at least 30 to 40 elements.
This is one case of "If it ain't broken, don't fix it".
Here is the most convenient way to find enum value by its field:
public enum TestEnum {
A("EXAMPLE_1", "Qwerty", 1),
B("EXAMPLE_2", "Asdfgh", 2),
C("EXAMPLE_3", "Zxcvbn", 3);
private final String code;
private final String name;
private final Integer typeID;
TestEnum(String code, String name, Integer typeID) {
this.code = code;
this.name = name;
this.key = typeID;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public Integer getKey() {
return key;
}
public static TestEnum findValueByTypeId(Integer key) {
return Arrays.stream(TestEnum.values()).filter(v ->
v.getKey().equals(key)).findFirst().orElseThrow(() ->
new Exception(String.format("Unknown TestEnum.key: '%s'", key)));
}
}
You should have a HashMap with the numbers as keys and the enum values as values.
This map can typically be in your repository. Then you can easily replace an int variable from the database with your preferred enum value.
If your keys (int values) are stored in a database, then I will say its bad design to carry those keys around in an enum on your business layer. If that's the case, I will recommend not to store the int value in the enum.
One solution is to add
public final Test[] TESTS = { null, ONE, TWO, THREE };
public static Test getByNumber(int i) {
return TESTS[i];
}
To the enum.
If the internal data is not an integer, you could have a Map which you populate in a static { ... } initializer. This map could later be used in the getByNumber method above.

Categories

Resources