When you look up a business in a phone book you utilize many of the core functionalities of Java’s HashMap without even knowing it. Consider a typical methodology for finding Joe’s Pizza Parlor in the Yellow Pages. First you look at the edge of the phone book and find the J section. You open the book to the J section and begin looking for Joe’s. Since ‘o’ is towards the middle of the alphabet, you cut the J’s section in half and turn to the middle of the section. In just two page flips, you are most likely within five pages of the listing you are looking for. You likely turn the page once or twice more and find Joe’s number. You have found the data you wanted and avoided looking at potentially millions of other pieces of data you didn’t care about. This is similar to the way that the HashMap works. The way that HashMap is implemented can have drastic affects on performance.
There has always been a simple problem with HashMaps. How are collisions handled in Java’s HashMap? For example, what if you had a phone book entirely full of businesses starting with the letter ‘J’? The way this collision is handled is significantly different between Java 7 and Java 8. The method Java 7 uses to handle the collision is to look through all of the businesses that start with ‘J’ beginning with the first and continuing until the business you are looking for is found. On average this means you must look through half of the businesses beginning with ‘J’ to find the listing you are looking for. In Java 8, the method is much closer to the method used in the example given above. After flipping to the ‘J’ section, you look for ‘Jo’, and then for ‘Joe’. At this point you can likely see the listing for Joe’s Pizza Parlor.
The new version of Java uses a balanced tree for collisions. Now, on average you only have to look through a logarithmic number of businesses beginning with ‘J’ to find the listing you are looking for. For instance, let’s suppose that there are 1,000 businesses beginning with ‘J’. In Java7 on average you will look through 500 listings before finding Joe’s Pizza Parlor. In Java 8, you will look through log_2(1,000) or roughly 10 listings. Even in this small case Java 8 will run roughly 50 times faster than Java 7. These marked improvements not only affect performance but can also avoid the need for additional hardware. You can see this for yourself by running the HashMapExample included here .
Java is often being used as a production web server environment and has proven to be an excellent language of choice for many companies. Many of the frameworks that are commonly used heavily rely on HashMaps to provide a basic lookup functionality. This is common in processing data the user has submitted. For Instance when a user submits a form on a website, many times that data will end up in a HashMap. Since Java7’s method of searching through the data can require looking through a lot of entries, it is possible for someone to exploit this knowledge to bring a web server to its knees. If someone simply submitted data that all ended up in the same section of a phone book, and you had to look through half of those entries on average to find one you’re looking for you can only imagine the issues that could be caused.
The new java.time package—which will serve as the main API for setting, processing, and manipulating dates and times—represents principal date/time concepts in the ISO calendar system, and all classes are immutable and thread-safe. In addition to this safety, a major benefit of the new java.time package is its readability. The new LocalDate, LocalTime, and LocalDateTime classes are intuitive and easy to work with:
LocalDateTime now = LocalDateTime.now(); // get the current date and time
now.toString(); // returns formatted date and time “2013-10-21T20:25:15:16.256”
LocalDateTime later = now.plus(5, HOURS); // add 5 hours
LocalDateTime earlier = now.minus(2, DAYS); // subtract 2 days
Additionally, the new API allows developers to easily calculate and store periods of time in either nanoseconds, using the Duration class, or in units more meaningful to humans (such as minutes, hours, days, etc.) using the Period class. For example:
LocalDate today = LocalDate.now();
LocalDate bday = LocalDate.of(1979, 3, 10);
Period timeAlive = Period.between(bday, today);
int age = timeAlive.getYears();
// Periods can also be used as arguments in the .plus() and .minus() methods:
LocalDate calculatedBday = today.minus(timeAlive);
Four additional packages are also included with JDK8 to aid in date/time manipulation. java.time.chrono includes a “calendar neutral” API to enable the use of, and conversion between, local calendars (e.g. Thai Buddhist calendar). java.time.format includes classes for printing and parsing date/time objects, although the individual classes’ .toString() and .parse() methods should be sufficient in most cases. java.time.zone includes additional classes to aid in the manipulation of time zones beyond the functionality of the ZonedDateTime, ZoneId, and ZoneOffsetclasses included in java.time. Finally, there’s my favorite – the java.time.temporal package, which includes interfaces for more powerful use cases. For example, the TemporalAdjuster functional interface allows developers to easily adjust dates:
LocalDate today = LocalDate.now();
LocalDate lastDayOfMonth = today.with(TemporalAdjuster.lastDayOfMonth());
LocalDate nextFriday = today.with(TemporalAdjuster.next(DayOfWeek.FRIDAY));
Java developers have complained about the unintuitive design and ambiguousness of the Calendar and Date classes, and the HashMap’s use of lists in collisions left them vulnerable to DOS attacks. With Java 8, both of these concerns have been significantly mitigated by new the java.time package and HashMap implementation, respectively.
Coming up in the Java 8 series is the fourth and final installment covering more improvements and bug fixes.
This post is part three of a series covering Java 8:
– Java 8 Part 1 – Lamdas, Streams, and Functional Interfaces
– Java 8 Part 3 – HashMap and java.time
– Java 8 Part 4 – Concurrency, TLS SNI, and PermGen