Join almost HALF A MILLION Happy Students Worldwide
Pianoforall is one of the most popular online piano courses online and has helped over 450,000 students around the world achieve their dream of playing beautiful piano for over a decade.
Oh, and it actually generates JPA entities from an existing database and gradually update the data model as the database evolves! Yeah .
More concretely, it provides powerful tooling to generate Spring Data JPA repositories and methods, Flyway Versioned Migrations, Liquibase Differential Changelogs, DDL and SQL statements, DTO objects, and MapStruct interfaces.
If you're using IntelliJ, JPA Buddy is super helpful . The plugin gently guides you through the subtleties of the most popular JPA implementations, visually reminds you of JPA features, generates code that follows best practices, and integrates intelligent inspections to improve your existing persistence code .
JPA is huge! It covers nearly every aspect of communication between relational databases and the Java application and is deeply integrated into all major frameworks.
Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.That's basically what Frontegg is -It's focused on making your app scalable, secure and enjoyable for your users.From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.
User management is very complex, when implemented properly. No surprise here.
Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.That's basically what Frontegg is -It's focused on making your app scalable, secure and enjoyable for your users.From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.
User management is very complex, when implemented properly. No surprise here.
If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines .
1. Introduction
In this quick guide, we're going to discuss the performance of the contains() method available in java.util.HashSet and java.util.ArrayList. They are both collections for storing and manipulating objects.
HashSet is a collection for storing unique elements. To learn more about the HashSet, check out this link.
ArrayList is a popular implementation of the java.util.List interface.
We have an extended article about the ArrayList available here.
2. HashSet.contains()
What are the 2 easiest chords on guitar?
Why E major and E minor are first two guitar chords you should learn first. 1. The E major and E minor open chord shapes can be moved up the guitar...
Internally, the HashSet implementation is based on a HashMap instance. The contains() method calls HashMap.containsKey(object).
Here, it's checking whether the object is in the internal map or not. The internal map stores data inside of the Nodes, known as buckets. Each bucket corresponds to a hash code generated with hashCode() method. So contains() is actually using hashCode() method to find the object's location.
Now let's determine the lookup time complexity. Before moving ahead, make sure you are familiar with Big-O notation.
On average, the contains() of HashSet runs in O(1) time. Getting the object's bucket location is a constant time operation. Taking into account possible collisions, the lookup time may rise to log(n) because the internal bucket structure is a TreeMap.
This is an improvement from Java 7 which used a LinkedList for the internal bucket structure. In general, hash code collisions are rare. So we can consider the elements lookup complexity as O(1).
3. ArrayList.contains()
Internally, ArrayList uses the indexOf(object) method to check if the object is in the list. The indexOf(object) method iterates the entire array and compares each element with the equals(object) method.
Getting back to complexity analysis, the ArrayList.contains() method requires O(n) time. So the time we spend to find a specific object here depends on the number of items we have in the array.
4. Benchmark Testing
Now, let's warm up the JVM with the performance benchmark test. We'll use the JMH (Java Microbenchmark Harness) OpenJDK product. To learn more about setup and execution, check out our useful guide.
To start, let's create a simple CollectionsBenchmark class:
@BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 5) public class CollectionsBenchmark { @State(Scope.Thread) public static class MyState { private Set employeeSet = new HashSet<>(); private List employeeList = new ArrayList<>(); private long iterations = 1000; private Employee employee = new Employee(100L, "Harry"); @Setup(Level.Trial) public void setUp() { for (long i = 0; i < iterations; i++) { employeeSet.add(new Employee(i, "John")); employeeList.add(new Employee(i, "John")); } employeeList.add(employee); employeeSet.add(employee); } } }
Here, we create and initialize HashSet and an ArrayList of Employee objects:
public class Employee { private Long id; private String name; // constructor and getter setters go here }
We add the employee = new Employee(100L, “Harry”) instance as the last elements to both collections. So we test the employee object's lookup time for the worst possible case.
What does Grade 8 singing mean?
Grade 8 is a sign that you've hit a good level of proficiency in one style of singing, but very few people who sing professionally (other than...
@OutputTimeUnit(TimeUnit.NANOSECONDS) indicates that we want the results in nanoseconds. The number of default @Warmup iterations are 5 in our case. The @BenchmarkMode is set to Mode.AverageTime, which means we're interested in calculating an average running time. For the first execution, we put iterations = 1000 items in our collections.
After, we add our benchmark methods to the CollectionsBenchmark class:
@Benchmark public boolean testArrayList(MyState state) { return state.employeeList.contains(state.employee); }
Here we check whether the employeeList contains employee object.
@Benchmark public boolean testHashSet(MyState state) { return state.employeeSet.contains(state.employee); }
Finally, we can run the test:
public static void main(String[] args) throws Exception { Options options = new OptionsBuilder() .include(CollectionsBenchmark.class.getSimpleName()) .forks(1).build(); new Runner(options).run(); }
Here are the results:
Benchmark Mode Cnt Score Error Units CollectionsBenchmark.testArrayList avgt 20 4035.646 ± 598.541 ns/op CollectionsBenchmark.testHashSet avgt 20 9.456 ± 0.729 ns/op
We can clearly see that the testArrayList method has 4035.646 ns average lookup score, while the testHashSet performs faster with 9.456 ns on average.
Now, let's increase the elements count in our test and run it for iterations = 10.000 items:
Benchmark Mode Cnt Score Error Units CollectionsBenchmark.testArrayList avgt 20 57499.620 ± 11388.645 ns/op CollectionsBenchmark.testHashSet avgt 20 11.802 ± 1.164 ns/op
Here also, the contains() in HashSet has a huge performance advantage over the ArrayList.
5. Conclusion
This quick write-up explains the performance of the contains() method of the HashSet and ArrayList collections. With the help of the JMH benchmarking, we've presented the performance of contains() for each type of collection.
As a conclusion, we can learn, that the contains() method works faster in HashSet compared to an ArrayList.
As usual, the complete code for this article is over on GitHub project.
Java bottom Get started with Spring 5 and Spring Boot 2, through the Learn Spring course: >> CHECK OUT THE COURSE