Do you want to count collections or know if they are empty?
TL;DR: Use declarative names. Always
Problems
Readability
Cache Invalidation
Performance Penalties
Type Safety
Solutions
- Replace count() == 0 and size()==0 usages
Context
isEmpty() and count()==0 seem to be equivalent but have deep differences.
The semantics are clearer.
Skipping this declarative method violating the collection encapsulation might have performance issues.
Sample Code
Wrong
import java.util.EmptyStackException;
import java.util.Stack;
public class SchrodingerStack<T> {
private Stack<T> stack;
public SchrodingerStack() {
stack = new Stack<>();
}
public void push(T item) {
stack.push(item);
}
public T pop() {
if (stack.size() == 0) {
throw new EmptyStackException();
}
T item = stack.pop();
return item;
}
public int size() {
return stack.size();
// This has O(n) linear time
// And the stack might not be fully reachable in memory
// While you wait, the stack isEmpty and notEmpty
// at the same time
}
public static void main(String[] args) {
SchrodingerStack<String> stack = new SchrodingerStack<>();
stack.push("Siamese");
stack.push("Garfield");
while (stack.size() > 0) {
System.out.println("Popped element: " + stack.pop());
}
if (stack.size() == 0 ) {
// Less readable
// violating encapsulation
// and coupled to the implementation
System.out.println("The stack is empty.");
} else {
System.out.println("The stack is not empty.");
}
}
}
Right
import java.util.EmptyStackException;
import java.util.Stack;
public class SchrodingerStack<T> {
private Stack<T> stack;
private boolean isEmpty;
public SchrodingerStack() {
stack = new Stack<>();
isEmpty = true;
}
public void push(T item) {
stack.push(item);
isEmpty = false;
}
public T pop() {
if (isEmpty()) {
throw new EmptyStackException();
}
T item = stack.pop();
if (stack.isEmpty()) {
isEmpty = true;
}
return item;
}
public boolean isEmpty() {
return isEmpty;
// This has O(1) constant time
}
public int size() {
return stack.size();
// This has O(n) linear time
// And the stack might not be fully reachable in memory
// While you wait, the stack isEmpty and notEmpty
// at the same time
}
public static void main(String[] args) {
SchrodingerStack<String> stack = new SchrodingerStack<>();
stack.push("Siamese");
stack.push("Garfield");
while (!stack.isEmpty()) {
System.out.println("Popped element: " + stack.pop());
}
if (stack.isEmpty()) {
// Semantic operation not violating encapsulation
System.out.println("The stack is empty.");
} else {
System.out.println("The stack is not empty.");
}
}
}
Detection
[X] Automatic
You can check for this expression using syntax abstraction trees.
Tags
- Readability
Level
[X] Beginner
AI Generation
LLMs generate abstractions using empty() functions
AI Detection
Gemini detected the problem of using count() == 0
Conclusion
Using IsEmpty() is recommended for checking if a collection is empty due to its clarity and potential performance benefits.
Relations
Code Smell 233 - Collections Count
Maxi Contieri ・ Dec 1 '23
Disclaimer
Code Smells are my opinion.
Credits
Photo by Valentin Lacoste on Unsplash
Good programming is good writing.
John Shore
Software Engineering Great Quotes
Maxi Contieri ・ Dec 28 '20
This article is part of the CodeSmell Series.