Related
First, please note that this question is not a duplicate of this Question:
Java Date vs Calendar. My question is much more specific. The referenced question asks "what" (or "which"), but I already know the "what" and am asking the "why".
I am on a team working on enhancements to an existing Java project for a client. This Java project uses java 6, and does not have Joda Time as a dependency. After inquiring, it looks like adding Joda Time or upgrading to Java 8 are not options.
So, when it comes to representing date/time as a field in an object, we have to use either Calendar or Date for property typing. The legacy code of this project is littered with Objects that use Calendar to represent date/time fields -- fields that we would never have cause to manipulate (as in add or subtract units of time, etc). I know that this is bad practice, as Calendar is a more complex object, while Date is simpler and would work just as well. (And granted, I know that both are fundamentally wrappers for a long of epoch millis, are mutable, and are poorly designed, but again these are our only two options.)
In other words, an object like this:
public class Reservation {
private Guest guest;
// Set only once, never used for calculations
private Calendar dateReserved;
...
}
Should be this instead:
public class Reservation {
private Guest guest;
// Set only once, never used for calculations
private Date dateReserved;
...
}
I then noticed that when adding new Objects for new features, my team was following the same convention of using Calendar instead of Date. When I brought this up, the reply was that it's better to use Calendar because it can do more and doesn't have all these deprecated methods like Date does.
I know that this reasoning is oversimplified. I also see that this answer to the broader question of usage expresses the same view, namely that Calendar should not be used for property typing. However, the answer doesn't contain much explanation as to why Calendar should not be preferred.
So I already know the "What". But I'm trying to make the case to my team, so my question is, "Why"? Why, when property typing, should Date be preferred to Calendar? What are the disadvantages of using Calendar instead of Date for property typing?
I agree with Jon Skeet's comment regarding calendar systems and time zones, and I think your premise is fundamentally flawed. Dates aren't better than Calendars. If you're never ever ever going to compare times, or never ever ever have two dates in different time zones, then sure, the smaller footprint can be nice, I guess, but at that point, just use longs and Unix timestamps. Calendars are by far the better object model, and after all, if you absolutely need it, you can get a Date object from it.
If you are stuck having to choose between Date and Calendar when property typing:
Use Calendar if either one of these is true:
You need to be able to adjust the date/time after it is initially set
(such as changing the month while leaving the day and hour the same).
You need to be aware of timezone.
Otherwise, use Date for the following reasons:
Expressing your intentions accurately. If you use Calendar, you are implying that you want a certain functionality that you don't actually intend to use (timezones, changing the day or month, etc).
Less hassle with String representations. For example, consider this class:
public class Reservation {
private Guest guest;
private Calendar dateReserved;
#Override
public String toString() {
return String.format("Reservation{guest=%s,dateReserved=\"%s\"}",
guest, dateReserved);
}
}
Now if you print out an instance of this class, you'll get something hideous:
Reservation{guest=Guest{id=17,name="John Smith"},dateReserved="java.util.GregorianCalendar[time=1426707020619,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=77,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=0,HOUR_OF_DAY=12,MINUTE=30,SECOND=20,MILLISECOND=619,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]"}
Whereas if you had used Date instead, you'd get this:
Reservation{guest=Guest{id=17,name="John Smith"},dateReserved="Wed Mar 18 12:34:26 PDT 2015"}
So if you use Calendar and you want your toString() to be usable, you would need to call dateReserved.getTime() -- which means you'd need to add a null check. This goes for whether or not you end up using a DateFormat object.
Date is a smaller object, quicker to instantiate and with less overhead.
Date is practically immutable -- meaning that the only way to change a date object is to use deprecated methods. So, as said in point 1, expressing your intentions matters. If your date field should be immutable, don't confuse developers who will touch your code in the future by using Calendar (unless of course you need timezone awareness).
"Date" is a more intuitive name than "Calendar" for the type of a field that represents a single point in time.
Date object has fewer fields and occupies less memory than Calendar object and is also faster to instantiate.
My question concerns a specific design convention for methods in Java... but really it would apply to C++, C# and others as well. I don't know what this convention is called, but if there is a standardized convention, I would like to know how to find it. In other words, I wish to describe this convention as I have encountered it and be directed to a place where I can learn more.
Consider java.util.Calendar, specificlaly its child, GregorianCalendar. It has an interesting "getter / setter" convention. Let's say that you instantiate this object:
GregorianCalendar cal = new GregorianCalendar();
The fields of cal now describe the instant in time (down to the millisecond) at which the constructor was called.
Now let's say that you want to access the year field or the month field. You would use the following getters.
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
Notice that it's not cal.getYear() or cal.getMonth(). It looks like there is only one getter method for this class and that the return value is determined by the parameter naming the desired field. I would imagine that within the class there is an enum set up to list the fields... and that the getter function itself is composed of some kind of switch statement.
This type of architecture is not described in any of my books... it is however something that I've been using in my current work... but I've been doing it "my" way (basically just making it up as I go along). If there is a standardized way of doing this that other people use... I'd sure love to know it. Specifically, using enums and switch statements to control the execution of methods.
Thanks so much for your time! This is my first question on this site... I have been a long time lurker though. :)
First, note that the two approaches to API design are not mutually exclusive: one could have both a "get by index" and a "get by name", i.e.
int y1 = cal.get(Calendar.YEAR);
int y2 = cal.getYear();
The primary driving force behind getters controlled by an int constant in the Calendar class is uniformity: it lets users of the Calendar class, such as the date formatters, build code that accesses the calendar by index, without further interpretation. For example, if you wanted to implement a formatter that takes a format string and stores a data structure to pull data from a calendar, you would be able to do it with an array of integers: "dd-mm-yyyy" would become int[] {Calendar.DAY, Calendar.MONTH, Calendar.YEAR}, and you would be able to get the data from calendar with a simple for loop.
Note that one of the reasons why Calendar uses integer constants instead of enums is backward compatibility: that Java did not have enum at the time when the Calendar class has been introduced.
Also note that you do not need a switch statement on an enum or int constants to implement Calendar's getters and setters: they can be implemented as direct reads and writes of the calendar component array.
Actually those are not enums. Those are integers instead. Here is the source code of the Calender get method:
public int get(int field)
{
complete();
return internalGet(field);
}
But having a single method accepting a ENUM and returning different values based on that, is good practice.
As far as the design pattern goes, IMHO it is a variation of Factory pattern.
I'm not actually aware of a name for this specific design, although I've seen it used in a few places. It's certainly not one of the standard "Design Patterns" and is really too small to qualify as a design pattern in its own right. It's just a different way of achieving encapsulation over the more traditional way with multiple getters and setters.
If I was to call it something it would probably be something like "flexible getter" or "extensible getter". I.e. "Rather than having multiple setters lets have one flexible getter"
If I was implementing something like this I would probably use the strategy pattern to do it though:
public abstract class Getter<T> {
private T getData(MyCalendar ob);
}
public static final Getter<Integer> MONTH {
Integer getData(MyCalendar ob) {
return ob.month;
}
}
Then your get method just looks like:
<T>public T get(Getter<T> toGet) {
return toGet.getData(this);
}
This uses polymorphism to fetch the data rather than a massive switch statement. It is fully flexible and extensible while still being type safe, etc.
I am a college student.
In our college we have to develop a simple Date class in Java similar to the one available in java.util package.
If we do that then what are the methods we can implement in that class,
Since most of the methods are deprecated in original Date class.
I saw the original Date class definitions in java/util/Date.java. Being a beginner to java, I could not understand the concepts of Serializable, Cloneable, Comparable ,and many variables like fasttime.
It will be good if we can implement this date class simply (since we have to develop this code as a test with in 3 hours at lab.)
Whether it is necessary to implement those concepts in a simple Date class.
If I take it as a Project and start developing the whole Date utilities,
then that code will run to many pages
and I cannot finish it with 3 hours for our lab session.
So someone please guide me....
I have doubts about....
Whether it is possible to create a utility class similar to Date class with a simpler implementation.
If we do that, then what are the methods we can implement in that class , since most of the useful methods are deprecated in the original date class.
Thanks in advance.
Serializable means the class can be Serialized to a transportable binary form.
Clonable means the class can be cloned, this is very tricky to get right, mainly because of inheritance and mutability concerns.
Comparable means the class supports being compared to other classes of the same type.
Of these Comparable is the only one that requires any code to function, it is also probably the only one that is any use in your scenario.
Serializable is what is called a Marker Interface it doesn't require any code to cause anything to happen since it doesn't have any methods to implement. It just exists to mark the object as supporting something and another class and check for this interface and do things based on its existence.
Cloneable is something you want to stay away from if at all possible. Cloning objects in Java is not straight forward, has lots of gotchas and generally behaves in the most non-intuitive ways imaginable. If you really want to know about this, learn about this, read this article.
Comparable is very valuable, it lets you compare to like objects to see if one is less than, equal or greater than another. This is a requirement for sorting and Collections classes that support Comparators. Comparators can be thought of as stand alone implementations of Comparable that can be plugged into other classes to control how objects are compared.
java.util.Date is a tricky class, it appears to be a straight forward struct type class with some mutators and convenience methods, but the underlying problem domain for calendar data isn't that simple. Calendar math has lots of exceptional cases. That is why there are so many methods on java.util.Date that are deprecated, they produced wrong behavior in many cases.
For some more code to study, look at this temporal package I developed to wrap the standard Java Calendar with very basic Date, Time and TimeStamp classes, they all just delegate to an instance of Calendar for the actual calcuations.
NOTE: this library code pre-dates JodaTime for those of you that might complain about just not using that library.
You don't have to implement all the interfaces to have a simple working Date class.
I would suggest that you forget about Java's Date class and consider what you think is needed for a date class. For example:
Get/set day of month
Get/set month
Get/set year
Get day of week
toString()
Would give you a pretty good basic date class.
For the sake of completeness, I'll tell you what the interfaces are for. You can decide whether to implement them based on how much you have learned and the assignment's requirements:
Serializable is for saving your object to a stream. You actually don't need to do much work to implement it.
Comparable is for comparing objects (date1.compareTo(date2) should return an integer indicating whether date1 is before, after, or the same as date2).
Clonable is for creating a deep copy of the object.
Since this is a lab project, why don't you list down what kind of function a 'simple' Date class needs and should have. For example, toString() -- returns a string representation of a Data or toMilliSecond() -- returns the number of milliSecond from the reference time.
What is really meant when using Java Date utilities and something has been deprecated. Does this mean that it is discouraged to use, or does it imply that it is forbidden?
I am guessing it is bad practice to use deprecated methods, but am not sure and wanted to find out.
For example, I am trying to use code such as the following
String date = request.getParameter("date");
model.setDate(new Date(date));
Of course...this is a high level example, but in this situation, my model uses type Date and I need to pull the date off the request as a String and create a date with it.
It works fine how I have it, but it is using a deprecated method.
EDIT - I have gone back and used
SimpleDateFormat formatter = new SimpleDateFormat();
model.setDate(formatter.parse(request.getParameter("date");
The date is in the format MM/DD/YYY like 07/23/2010 but I am getting a ParseException
What could this be from?
You're right that this is bad practice. In almost all cases, deprecated methods tell you what to use instead, and this is no exception (see the Javadocs).
You're trying to create a Date out of a String. But what format is the String in? How should it be parsed? Is it UK or US date format?
The "proper" way to do this is to create an instance of SimpleDateFormat, and call its parse() method passing in your text string. This is guaranteed to work in future, and will be more robust now.
A lot of people have mentioned what Deprecated means, but I don't see any explanation of why these methods are deprecated:
Sun (before they were part of Oracle) deprecated a number of methods in Date to get people to use the Calendar/GregorianCalendar classes for date manipulation instead.
Deprecated objects or methods merely means that if you want to use it in current project, rather use what is recommended. The reason why they still have it is for legacy codes who have used the deprecated method before it was deprecated. Typical example is StringTokenizer vs String.split() method.
For your Date example use SimpleDateFormat to do conversion from String to Date. This allows you to create a date format from which your string date can be parsed to create a Date object.
For your EDIT do this
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
model.setDate(formatter.parse(request.getParameter("date")));
ParseException is caused since you didn't provide a date format structure so the SimpleDateFormat didn't know how your date was structured.
What "Deprecated" Means
You may have heard the term,
"self-deprecating humor," or humor
that minimizes the speaker's
importance. A deprecated class or
method is like that. It is no longer
important. It is so unimportant, in
fact, that you should no longer use
it, since it has been superseded and
may cease to exist in the future.
Java provides a way to express
deprecation because, as a class
evolves, its API (application
programming interface) inevitably
changes: methods are renamed for
consistency, new and better methods
are added, and fields change. But such
changes introduce a problem. You need
to keep the old API around until
developers make the transition to the
new one, but you don't want them to
continue programming to the old API.
The ability to deprecate a class,
method, or member field solves the
problem. Java supports two mechanisms
for deprecation: and an annotation,
(supported starting with J2SE 5.0) and
a Javadoc tag (supported since 1.1).
Existing calls to the old API continue
to work, but the annotation causes the
compiler to issue a warning when it
finds references to deprecated program
elements. The Javadoc tag and
associated comments warn users against
using the deprecated item and tell
them what to use instead.them what to use instead.
http://download-llnw.oracle.com/javase/1.5.0/docs/guide/javadoc/deprecation/deprecation.html
You are right, Its discouraged to use deprecated methods.
This is because these methods may have issues in some situation or have been replaced with more optimistic solutions And also future versions may not support these.
Deprecated means it is planned for removal, because it is buggy or some other bad reason.
It is better to use SimpleDateFormat.parse(); to parse your strings.
In general, when Sun (Oracle, whatever) declares a Java method deprecated, it means that they changed their minds about including it, they discourage you from using it, and they may remove it in some future version. Of course it's likely to be a long time before it gets removed as who knows how much existing code there is out there using it, and what's the point of breaking existing programs just because the inventors of Java think they now have a better idea about how to do something?
Presumably they had a good reason for deprecating something, so you should investigate WHY they say that some newer function is better.
In the case of deprecated Date methods, usually this means that they suggest you now use the Calendar or SimpleDateFormat classes. In your case, probably the latter.
deprecated: something that exists in the current version of Java, but will be removed from future versions at some point.
For your edit, you need to properly initialize the SimpleDateFormat, so it knows what format is coming in. For 07/22/1978 format:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
As other said, the java.util.Date methods were deprecated because the Java team believed they had a better solution in the java.util.Calendar.
Unfortunately that class also proved to be confusing, troublesome, and poorly designed.
So, yes, you should avoid deprecated methods in deference to their replacements. But now those replacements (.Calendar) have a replacement (java.time).
java.time
All the old date-time classes have been supplanted by the java.time framework built into Java 8. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
Use the java.time.format package for parsing and generating String representations of date-time values.
String input = "07/23/2010";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MM/dd/yyyy" );
The new classes include LocalDate for representing a date-only value without time-of-day.
LocalDate localDate = LocalDate.parse( input , formatter );
If you call toString on a LocalDate you get a String representation of the date value in the standard ISO 8601 format, YYYY-MM-DD. To generate a String in other formats, define another formatter. Or call the 'localize' methods to let java.time do the heavy lifting in determining a particular localized format.
Nothing will break if you use them...yet.
But they may well be removed in future versions.
In Java, an Enum can do the great things that Enums do, but can also have methods (behavior and logic). What advantage does that have over using a class using an enum? Simple examples to illustrate the point would also be welcome.
Here's a simple example:
enum RoundingMode {
UP {
public double round(double d) {
return Math.ceil(d);
}
},
DOWN {
public double round(double d) {
return Math.floor(d);
}
};
public abstract double round(double d);
}
Enum types are also a great way to implement true singletons.
Classic singleton patterns in Java typically involve private constructors and public static factory methods but are still vulnerable to instantiation via reflection or (de-)serialization. An enum type guards against that.
I'm not quite sure where the title of the question fits in with the rest of it. Yes, Java enums have behaviour. They can have state too, although it should really, really be immutable state. (The idea of a mutable enum value is pretty scary IMO.)
An enum in Java is a fixed set of objects, basically. The benefit is that you know that if you have a reference of that type, it's always either null or one of the well-known set.
Personally I really love Java enums and wish C# had them too - they're much more object-oriented than C#'s enums which are basically "named numbers". There are a few "gotchas" in terms of initialization order, but they're generally fab.
Because the enum instances are singletons, you can use them in switch statements or with == to check equality.
Basically, Java enums are classes (I don't believe there is a difference at the bytecode level), with the additional benefit of having a known fixed set of possible instances and being able to use them in switch statements.
You can emulate the "known fixed set of possible instances" with regular classes (the "typesafe enum" pattern described in countless books and articles), but it's quite some work (repeated for every such class) to get it to work really correctly in regard to Serialization, equals() and hashCode(), and perhaps some other things I forgot. Language-level enums spare you that work. And, as mentioned above, only language-level enums can be used in switch statements.
In our project, we're using Enums for a few things, but perhaps most prominently for i18n purposes - each piece of shown text is given an Enum. The Enum class has a String-returning method that inspects the Locale that is being used, and picks the correct translation from a collection of translations on runtime.
This serves as a dual-purpose - you get code completion from your IDE, and also never forget to translate a string.
The usage is very simple, to the point that it's almost rendundant to give an example, but here's how one might use the translation-enum
System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName());
Or, if you want to be fancy, have the Enum accept arguments, which will, with some magic string manipulation, be inserted in a marked position in the translations string
System.out.println(Translations.GREET_PERSON.trans(user.getName());
Take a look at java/joda time classes, where enums do hell of a lot of job.
Here is an example of java.time.Month:
public enum Month implements TemporalAccessor, TemporalAdjuster {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
private static final Month[] ENUMS = Month.values();
public static Month of(int month) {
if (month < 1 || month > 12) {
throw new DateTimeException("Invalid value for MonthOfYear: " + month);
}
return ENUMS[month - 1];
}
// About a dozen of other useful methods go here
}