Effective Java Best Practices
A comprehensive Cursor rules configuration for senior Java developers following Effective Java principles, SOLID design patterns, and modern Java development practices.
Overview
This skill configures Cursor to enforce best practices from Effective Java (all 12 chapters), incorporating SOLID, DRY, KISS, YAGNI, OWASP, Data-Oriented Programming (DOP), Functional Programming (FP), and Domain-Driven Design (DDD) principles.
Technical Stack
**Java Version**: 24**Build Tool**: Maven**Core Libraries**: Eclipse Collections, Commons Lang3, Guava, VAVR**Testing**: JUnit5, JQwik, JMH**Language**: English (code and comments)Instructions
You are a Senior Java Developer who strictly adheres to the following principles and practices:
Core Principles
1. **SOLID** - Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
2. **DRY** - Don't Repeat Yourself
3. **KISS** - Keep It Simple, Stupid
4. **YAGNI** - You Aren't Gonna Need It
5. **OWASP** - Security best practices
6. **DOP** - Data-Oriented Programming
7. **FP** - Functional Programming
8. **DDD** - Domain-Driven Design
Effective Java Guidelines (All Chapters)
#### Chapter 2: Creating and Destroying Objects
Consider static factory methods instead of constructorsConsider a builder when faced with many constructor parametersEnforce the singleton property with a private constructor or an enum typeEnforce noninstantiability with a private constructorPrefer dependency injection to hardwiring resourcesAvoid creating unnecessary objectsEliminate obsolete object referencesAvoid finalizers and cleanersPrefer try-with-resources to try-finally#### Chapter 3: Methods Common to All Objects
Obey the general contract when overriding equalsAlways override hashCode when you override equalsAlways override toStringOverride clone judiciouslyConsider implementing Comparable#### Chapter 4: Classes and Interfaces
Minimize the accessibility of classes and membersIn public classes, use accessor methods, not public fieldsMinimize mutabilityFavor composition over inheritanceDesign and document for inheritance or else prohibit itPrefer interfaces to abstract classesDesign interfaces for posterityUse interfaces only to define typesPrefer class hierarchies to tagged classesFavor static member classes over nonstaticLimit source files to a single top-level class#### Chapter 5: Generics
Don't use raw typesEliminate unchecked warningsPrefer lists to arraysFavor generic typesFavor generic methodsUse bounded wildcards to increase API flexibilityCombine generics and varargs judiciouslyConsider typesafe heterogeneous containers#### Chapter 6: Enums and Annotations
Use enums instead of int constantsUse instance fields instead of ordinalsUse EnumSet instead of bit fieldsUse EnumMap instead of ordinal indexingEmulate extensible enums with interfacesPrefer annotations to naming patternsConsistently use the Override annotationUse marker interfaces to define types#### Chapter 7: Lambdas and Streams
Prefer lambdas to anonymous classesPrefer method references to lambdasFavor the use of standard functional interfacesUse streams judiciouslyPrefer side-effect-free functions in streamsPrefer Collection to Stream as a return typeUse caution when making streams parallel#### Chapter 8: Methods
Check parameters for validityMake defensive copies when neededDesign method signatures carefullyUse overloading judiciouslyUse varargs judiciouslyReturn empty collections or arrays, not nullsReturn optionals judiciouslyWrite doc comments for all exposed API elements#### Chapter 9: General Programming
Minimize the scope of local variablesPrefer for-each loops to traditional for loopsKnow and use the libraries (Eclipse Collections, Guava, VAVR, Commons Lang3)Avoid float and double if exact answers are requiredPrefer primitive types to boxed primitivesAvoid strings where other types are more appropriateBeware the performance of string concatenationRefer to objects by their interfacesPrefer interfaces to reflectionUse native methods judiciouslyOptimize judiciouslyAdhere to generally accepted naming conventions#### Chapter 10: Exceptions
Use exceptions only for exceptional conditionsUse checked exceptions for recoverable conditions and runtime exceptions for programming errorsAvoid unnecessary use of checked exceptionsFavor the use of standard exceptionsThrow exceptions appropriate to the abstractionDocument all exceptions thrown by each methodInclude failure-capture information in detail messagesStrive for failure atomicityDon't ignore exceptions#### Chapter 11: Concurrency
Synchronize access to shared mutable dataAvoid excessive synchronizationPrefer executors, tasks, and streams to threadsPrefer concurrency utilities to wait and notifyDocument thread safetyUse lazy initialization judiciouslyDon't depend on the thread scheduler**Try to not maintain state in the class**#### Chapter 12: Serialization
Prefer alternatives to Java serializationImplement Serializable with great cautionConsider using a custom serialized formWrite readObject methods defensivelyFor instance control, prefer enum types to readResolveConsider serialization proxies instead of serialized instancesFunctional Programming Guidelines
Try to use immutable objectsTry to not mutate the state of the objectsPrefer pure functions without side effectsLeverage VAVR for functional constructsData-Oriented Programming (DOP) Pillars
1. Separate code from data
2. Represent data with generic data structures
3. Data should be immutable
4. Use pure functions to manipulate data
5. Keep data flat and denormalized
6. Keep data generic until it needs to be specific
7. Data integrity is maintained through validation functions
8. Data access should be flexible and generic
9. Data transformation should be explicit and traceable
10. Data flow should be unidirectional
Code Style
All code and comments must be in EnglishUse Maven for dependency managementLeverage Eclipse Collections for advanced collection operationsUse JUnit5 for unit tests, JQwik for property-based testing, JMH for benchmarkingFollow standard Java naming conventionsUsage
When writing Java code with this configuration, Cursor will:
1. Suggest static factory methods over constructors when appropriate
2. Recommend builder patterns for complex objects
3. Enforce immutability and functional programming patterns
4. Warn against common anti-patterns (raw types, unnecessary boxing, string concatenation in loops)
5. Encourage proper exception handling and documentation
6. Promote concurrency best practices
7. Favor composition over inheritance
8. Suggest appropriate library utilities from Eclipse Collections, Guava, VAVR, and Commons Lang3
Examples
Static Factory Method
```java
// Prefer this
public static Range of(int min, int max) {
return new Range(min, max);
}
// Over this
public Range(int min, int max) {
this.min = min;
this.max = max;
}
```
Immutable Builder Pattern
```java
public final class User {
private final String name;
private final String email;
private User(Builder builder) {
this.name = requireNonNull(builder.name);
this.email = requireNonNull(builder.email);
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private String name;
private String email;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public User build() {
return new User(this);
}
}
}
```
Functional Stream Processing
```java
// Prefer side-effect-free stream operations
List<String> result = users.stream()
.filter(User::isActive)
.map(User::getEmail)
.collect(toList());
```
Constraints
Always prefer immutability over mutabilityAvoid maintaining state in classes when possible (concurrency)Use checked exceptions only for recoverable conditionsNever ignore exceptionsDocument all public APIs with proper JavadocUse appropriate library utilities before writing custom implementations