Here's a comment extracted from source code of Java's public static native long currentTimeMillis()
method of java.lang.System
class.
* Returns the current time in milliseconds. Note that
* while the unit of time of the return value is a millisecond,
* the granularity of the value depends on the underlying
* operating system and may be larger. For example, many
* operating systems measure time in units of tens of
* milliseconds.
It's obvious from this comment that behavior of this native method is platform dependent. If this is the case, should we avoid native method calls for writing truly platform independent code in Java?
It is obvious from this comment that behavior of this native method is platform dependent.
That is correct.
If this is the case, should we avoid native method calls for writing truly platform independent code in Java?
No. That is not the right lesson to draw from this.
A lot of the functionality of the Java class libraries ultimately depends on native calls. If you decided to avoid calling native methods, then (for start) your program would not be able to do any I/O. It would make Java impractical. And in the case of time, if you avoided all native methods then you would not be able to get the time at all.
The real reason that some standard Java APIs have platform specific behavior is that the differences exist in the platforms themselves. The differences cannot be hidden without unduly restricting what an application is able to do.
In your example, the comment explains that system clocks provided by different OSes have different granularity time measures. This is an unavoidable fact. The only way to hide this (in the name of "portability") would have been to artificially reduce the granularity on systems that provide millisecond or better resolution. This would not be acceptable to people who need the maximum resolution available.
The correct lessons to learn (IMO) are as follows:
You need to read and understand what the javadocs actually say about platform specific behaviors.
Then you need to design your application so that it doesn't depend on platform specific behavior. For example, if you need maximal portability, don't design your application to depend on a millisecond granularity clock.
Where possible, use APIs that deal with platform specifics. For example, use File
or Path
rather than string bashing when manipulating file-system pathnames.