How do I use methods with optional data - java

I have created a class called Person which uses Optional<LocalDate> to store a person's birthday as a field. I have a method called timeToNextBirthday which computes the interval between the time of calling and the next birthday. The problem I'm having is that since birthday is optional, the method sometimes has nothing it can return. I don't know if I should throw an exception or just return some default object. I also considered making the return type optional and returning an empty optional if the birthday is unknown. This is a snippet of my code so far, using the exception option.
public class Person {
private Optional<LocalDate> dateOfBirth;
public Period timeToNextBirthday() throws NoSuchElementException {
if(!dateOfBirth.isPresent()) {
throw new NoSuchElementException("Birthday is unknown");
}
LocalDate currentDate = LocalDate.now();
// Assume this year's birthday has not passed and set next birthday to this year
LocalDate nextBirthday = dateOfBirth.get().withYear(currentDate.getYear());
// Add a year to nextBirthday if this year's birthday has already passed or is today
if (currentDate.isAfter(nextBirthday) || currentDate.equals(nextBirthday)) {
nextBirthday = nextBirthday.plusYears(1);
}
return Period.between(currentDate, nextBirthday);
}
}
How should I proceed?

Consider this: Changing the method's return type to Optional<Period> would make it very clear to the user of this method that it may not result in an usable Period due to dateOfBirth being optional and the user space code must be made to accomodate for this fact.
This sort of type carry-over is just fine if you don't want to throw exceptions (like you currently do) as it allows you as an API designer to assist the user of your code to cover all bases in a secure, null safe and self documenting way. Of course writing a bit of javadoc explaining why the return type is wrapped in Optional won't hurt either :)

Related

What is guardian code?

My lecturer started to refer to something called guardian code in our reading material. In case it helps, this is a Java beginners module. Here are some references to in the text.
Since there are no mutators and therefore no mutator guardian code the guardian code is forced into the constructor (as a call to the validateDate(…) private helper method). The constructor would usually call the mutators to check initial values received as constructor parameters were valid before assigning them their respective instance variables.
Any help would be greatly appreciated
Thanks!!
The text refers to code that provides parameter validation, "guarding" the object from entering a bad state.
Fox example, if you are building a class with a String property called serialNumber that must be seven to nine characters long, you would add a setter like this:
void setSerialNumber(String sn) {
if (sn == null || sn.length() < 7 || sn.length() > 9) {
throw new IllegalArgumentException("sn");
}
serialNumber = sn;
}
if in the code snippet above is "guardian code". The textbook says that when the class is mutable, this guardian code goes into setters. However, when the class is immutable, you move this code into the constructor:
MyObject(String sn) {
if (sn == null || sn.length() < 7 || sn.length() > 9) {
throw new IllegalArgumentException("sn");
}
serialNumber = sn;
}
Your lecturer likely meant guard code. This adds an extra defensive layer of validation to ensure that the data you're either receiving or sending off is not invalid in any way. In general, one writes guard code to ensure that a value that they require isn't null (to prevent NullPointerExceptions), or is within an expected range - although that's a broader discussion on validation.
As an example, if I were writing a method called boolean validateDate(Date date), one piece of guard code I'd write is:
public boolean validateDate(Date date) {
if(null == date) {
throw new IllegalArgumentException("Date can't be null");
}
// other logic to follow
}

using the date type in java

I am trying to get two dates from a SQL query, and compare them. So to compare them, I believe I will need to use the "Date" type. Here is what I am trying, I know I am getting the date from the resultSet incorrectly, but I am not sure how to do it.
Date validDate = new Date(0);
Date currentDate = new Date(0);
// query
if (result.next()) {
validDate = (result.getObject("validDate")!=null)?result.getObject("validDate").toDate():"";
currentDate = (result.getObject("currentDate")!=null)?result.getObject("currentDate").toDate():"";
}
if (currentDate > validDate) {
//do something
}
So again, this was my attempt, but I cant seem to get it to run. Thanks in advance.
EDIT: the query has TO_CHAR(column, 'MM-DD-YYYY') on the two dates that I am getting.
EDIT: Now you've mentioned that your query converts the date to a string, stop doing that. You'll end up reparsing it on the calling side - so why perform two conversions pointlessly? Keep string conversions to the absolute minimum - stay in the most appropriate data type wherever possible.
Original answer
You haven't shown what result is, but you probably want something like ResultSet.getDate() to fetch the date values.
Note that your comparison code won't work either because there's no > for Date - you'd need something like:
if (currentDate.after(validDate))
Or fetch the underlying number of millis:
if (currentDate.getTime() > validDate.getTime())
Additionally:
You can't assign "" to a Date variable - a string isn't a Date.
You can just call ResultSet.getDate() and check whether the returned value is null, rather than calling getObject first and then getDate()
Try currentDate.after(validDate)
To compdare dates I always use the before and after methodes of Date.
Some nasty things can happen when accessing dates via the getObject method. You should try to use the rs.getTimestamp (with timeinfo) or the rs.getDate (without timeinfo) methods.
Also, because of the rather complex hierarchy of Date-objects you should compare Dates only using the date1.compareTo(date2) > 0 method.
if your result object is ResultSet, then
Date validDate = result.getTimestamp("validDate");
Date currentDate= result.getTimestamp("currentDate");
// you can add null checks here too....
// you can also use if (currentDate.getTime() > validDate.getTime()){}
if (currentDate.before(validDate)) {
//some code inhere...
}
There are at least three things wrong with your code:
"" is a String literal, so you cannot use it int your ternary expressions to be assigned to a variable of type Date - use null instead so you don't need a ternary
ResultSet.getObject() returns an Object, which does not have a toDate() method. Instead, simply use ResultSet.getDate()
You cannot compare Date instances using a > operator. You have to use the before() and after() methods of the Date class
Taking all this together, the following code might work:
Date validDate = new Date(0);
Date currentDate = new Date(0);
if (result.next()) {
validDate = result.getDate("validDate");
currentDate = result.getDate("currentDate");
}
if (currentDate.after(validDate)) {
//do something
}
The if clause may have to include some extra logic to deal with null values though. It's better to do that than to leave that to implicit conversions, too.

Java Enum.valueOf() efficiency when value does not exist

Which would you consider more efficient?
The use of 'WeekDay' is just an example:
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
}
Loop through and verify day string first:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
if (isValidWeekDay(day)) {
WeekDay weekDay = WeekDay.valueOf(day); // won't throw exception
...
} else {
throw new InvalidWeekDayException(day); // subclass of RuntimeException
}
}
private boolean isValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return true;
}
return false;
}
Or since in 99.99% of cases, day will be correct:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day, e);
}
}
Update:
To clarify, the input string will come from a client application, rather than a user. So in other words, it would be a bug to recieve a non workday in this example.
As has been commented, you will have to profile to find out for sure. Even in your own parsing approach, you can make it faster by returning the enum when you parse the list.
private WeekDay getValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return weekDay;
}
return null;
}
Unless this is a time critical piece of an application, I wouldn't worry about it in either case and simply take the most readable approach. I think that would be using the WeekDay.valueOf() method.
If you would rather not have to deal with exceptions, then create a Map of your values within the enum and effectively do the equivalent of valueOf() from a lookup which returns null if it is not found.
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
private static Map<String, WeekDay> valueMap;
public static WeekDay getValue(String possibleName)
{
if (valueMap == null)
{
valueMap = new HashMap<String, WeekDay>();
for(WeedDay day: values())
valueMap.put(day.toString(), day);
}
return valueMap.get(possibleName);
}
}
This is effectively what the valueOf() method is doing anyway, except it throws the IllegalArgumentException when it is not found. This approach will simply return null, thus not generating the stacktrace.
What is the performance concern about the 2nd approach? Catching an exception like that costs almost nothing. Using exceptions for normal control flow is generally a bad idea from a design perspective, the days where this was a performance consideration are long gone. In a debugger, using exceptions as significant control operations will slow things down by a factor of about 10. But this gets optimized by the JIT and there is no measurable impact in production.
These numbers are based on experience with an evaluation I did of the zxing project, which uses exceptions for all sorts of flow control. When I first saw it, I was horrified. I still think it's not the best design, but I did quite a bit of testing and can say with a good bit of confidence that it had no real impact on performance. And this is an algorithm that was using exceptions all over the place for flow control. Your situation, where the exception will only get thrown in highly exceptional circumstances, is a non issue.
Edit: I've had a downvote or two on my answer, and I want to make sure that I'm super clear on what I'm saying: I do not think that it's a good idea to use exceptions for normal control flow. Just because performance is not a good argument for not using exceptions this way doesn't mean that there aren't other, perfectly valid reasons (such as readability, testability, extendability). In the case of the OP, the use of an exception is absolutely called for, and definitely wouldn't cause any sort of performance issue.
I know its an old post, but I believe following result will be still interesting. I run 10000000 tests to find an element in enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST} using JDK 1.8. The table below shows time required by simple loop and valueOf().
text loop valueOf ratio
------------------------------
"FIRST" 121 65 186%
"LAST" 188 57 330%
"foo" 155 8958 1.7%
Conclusion - I wouldn't use valueOf() if I expect values not matching enum.
If your question is really about the efficiency of searching among 7 item you have already wasted too much time on it. Even the fastest search algorithms yield zero or negative benefits until N > 15 or so, other than the O(1) one.
Store the valid strings in a HashSet, and decide whether a string is a valid day or not based on Set.contains(...).
The set can be a static final Set, and you can wrap in an unmodifiable for good measure:
private static final Map<String> WEEKDAY_STRINGS;
static {
HashSet<String> set = new HashSet();
for (WeekDay d : WeekDay.values()) {
set.add(d.toString());
}
WEEKDAY_STRINGS = Collections.unmodifiableSet(set);
}
The loop doesn't do anything that calling valueof doesn't, they have the same functionality : checking whether your string is valid enum. What do you think you gain from the first option ?
The second option is best:
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day);
}
Or you could create a lookup of enum values inside your enum when the class first loads(see static modifier) and validate using get() as shown below:
private String dayName;
private static final Map<String,Weekday> lookup = new HashMap<String, Weekday>();
static{
for (Weekday day: values()){
lookup.put(day.dayName, d);
}
}
public static Weekday get(String _name){
return lookup.get(_name);
}
Let me know if you need more details

How to initialize Mock with variable data

I have this method to test :
public static Date getDateSinceUTC(CstOrderBean orderBean) {
int year = orderBean.getDeadLineYear();
int month = orderBean.getDeadLineMonth();
int day = orderBean.getDeadLineDay();
int hour = orderBean.getDeadLineHour();
int minute = orderBean.getDeadLineMinute();
String ap = orderBean.getDeadLineAmPm() == 1 ? "PM" : "AM";
//TODO AM=0, PM=1 comes from html form
SimpleDateFormat df = new SimpleDateFormat("yyyy:MM:dd:hh:mm:aa");
String stringDate = stringifyIntegers(":", year, month, day, hour, minute);
stringDate = stringDate.concat(ap);
Date date;
try {
date = df.parse(stringDate);
} catch (ParseException e) {
throw new Error("Parsing date from html form failed", e);
}
return date;
}
Where CstOrderBean needs to be mocked by Mockito because it is not a POJO (some static initializations etc. - from source code generator). But I need to run the method xxx times, hence set the mocks with many data combinations
I could use TestNG's #DataProvider to do that. But I'm not sure how to do that, I guess that :
when(ob.getDeadLineYear()).thenReturn(1, 2, 3);
....
in loop is a bad idea, isn't it ? Is the correct way of doing this to create xx mocks and initialize them like that ?
Each test should get their own mock that preferably does not have variable data. If you use several different return values from the same mock object then the testing has to be white-box testing as the test is coupled with the number of calls to a mocked method instead of the result of the method under test.
That said, you are able to define a set of return values with calling thenReturn repeatedly or by defining the return values as varargs
when(ob.getDeadLineYear()).thenReturn(someValue, anotherValue, ..., ultimateValue);
This might be cleaner as you should probably control the values that the mock returns anyway.
How you mock depends on what you would like to test. Looping on the deadline year might not do the job you want it to.
One test for seeing if a leap year works might be something like:
when(ob.getDeadLineYear()).thenReturn(2000);
when(ob.getDeadLineMonth()).thenReturn(2);
when(ob.getDeadLineDay()).thenReturn(29);
when(ob.getDeadLineHour()).thenReturn(12);
when(ob.getDeadLineMinute()).thenReturn(0);
when(ob.getDeadDeadLineAmPm()).thenReturn(1);
assertTrue("Got unexpected date", getDateSinceUTC(ob).toString().startsWith("2000-02-29 12:00:00"));
(Warning: above codes was typed in by hand). Mix, match, and repeat for other dates that you need to test to verify that getDateSinceUTC is working. You might want a separate test method to check invalid dates, like 2/30/2012 (and expect a throw). You might want to check invalid times like 23:61. You might want to check valid dates, like your birthdate.
Instead of a loop on the year, please look at "normal" cases, borderline cases, and error cases. This is the better practice for unit testing.

Throwing exception vs returning null value with switch statement

So I have function that formats a date to coerce to given enum DateType{CURRENT, START, END}
what would be the best way to handling return value with cases that use switch statement
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
default:throw new ("Something strange happend");
}
}
OR throw excpetion at the end
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
}
//It will never reach here, just to make compiler happy
throw new IllegalArgumentException("Something strange happend");
}
OR return null
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
}
return null;
}
What would be the best practice here ? Also all the enum values will be handled in the case statement
Throw an exception, since this is an exceptional case.
And throw it outside the switch, it would be more readable. Otherwise it sounds like "the default case is exceptional".
I think that throw new IllegalArgumentException("Something strange happend") is the best pratice.
Using null will just presumibly cause a NullPointerException somewhere when you use the return value but it will be less informative than raising a specific exception that describes the problem!
And you know: clear errors = better developing.
I would go with the first approach (but with IllegalArgumentException as in your second approach). You should include a default statement to guard against cases when someone modifys (extends) your enum. Putting the exception in the default-statement makes clear to the reader that the code is never supposed to get past the switch-statement. Otherwise they would have to check if really all of the enum values are in the switch.
Exceptions, as you can obey more to the parent than a single return int can. Usually you use Exceptions where they exist (C++), and return values where not (C).

Categories