miscellaneous

Java Cheatsheet when transistioning from C++

Transitioning from C++ to Java often requires a solid reference for the syntactic differences and Java conventions.


☕ Core Java Syntax & Concepts

ConceptC++ Syntax/StyleJava Equivalent/ConventionNotes
Basic Outputstd::cout << "Hi";System.out.println("Hi");Use System.out.printf() for C-style formatted output.
Header/Include#include <iostream>import java.util.List;Java uses import statements for classes/packages.
Primitive Typesint, double, boolint, double, booleanboolean (lower case) is a primitive. Java has no unsigned types.
Main Methodint main() { ... }public static void main(String[] args) { ... }Mandatory signature for the entry point.
Object CreationMyClass* obj = new MyClass();MyClass obj = new MyClass();Java uses automatic memory management (Garbage Collection), so no manual delete is needed.
String Concatenation"A" + std::to_string(i)"A" + iThe + operator is overloaded for string concatenation.

🧩 Variables & Data Structures

1. Primitives vs. Wrappers

Java distinguishes between primitive types (for performance) and wrapper classes (for use in Collections).

Primitive TypeWrapper ClassSizeDefault Value
intInteger32-bit0
longLong64-bit0L
booleanBoolean1-bitfalse
charCharacter16-bit (Unicode)\u0000
floatFloat32-bit0.0f
doubleDouble64-bit0.0d

Autoboxing/Unboxing: Java automatically converts between primitives and their wrappers (e.g., int i = new Integer(5) works seamlessly).

2. Arrays, Strings, and Collections (The Indexing Reference)

Data StructureCreation / DeclarationSize PropertyElement AccessNotes
Native Arrayint[] arr = new int[5];arr.length (Field)arr[i] (Square brackets)Fixed size.
StringString s = "data";s.length() (Method)s.charAt(i) (Returns char)Immutable.
List (ArrayList)List<T> list = new ArrayList<>();list.size() (Method)list.get(i) (Method)Dynamic size. Requires wrapper classes (T).
Map (HashMap)Map<K, V> map = new HashMap<>();map.size() (Method)map.get(key) (Method)Key-value pairs. Use map.put(k, v) to insert.

🧱 Object-Oriented Programming (OOP)

ConceptJava Implementation DetailsC++ Contrast
InheritanceUses extends keyword. Java has single inheritance for classes.Uses : or virtual keywords. C++ supports multiple inheritance.
InterfacesUse interface keyword and implement with implements. Can implement multiple interfaces.C++ uses Abstract Base Classes with purely virtual methods to achieve a similar goal.
EncapsulationUse Access Modifiers (public, private, protected, default).Similar, but Java’s default (package-private) is distinct.
ConstructorsSame name as the class. Use this() to call another constructor in the same class.Similar, but Java strictly prohibits manual memory allocation/deallocation (new/delete).
Method OverridingUse the @Override annotation (highly recommended). All non-static methods are virtual by default.Must explicitly use the virtual keyword in the base class in C++.
Final KeywordUsed for classes (cannot be inherited), methods (cannot be overridden), or variables (constant).Similar to const in C++.

Access Modifiers

ModifierClassPackageSubclassWorld
publicYesYesYesYes
protectedYesYesYesNo
(default)YesYesNoNo
privateYesNoNoNo

🌐 Modern Java Features (Since Java 8)

FeatureSyntax ExampleUse Case (Relevant to Backend)
Lambda Expressions(a, b) -> a + bConcise implementation of functional interfaces (e.g., Spring framework callbacks).
Streamslist.stream().filter(i -> i > 5).collect(Collectors.toList());Performing chained, efficient, and often parallel processing on collections.
OptionalsOptional<String> name = Optional.ofNullable(val); name.ifPresent(System.out::println);Handling potential null values gracefully to prevent NullPointerException (a common Java error).
Records (Since Java 14)public record User(String name, int id) {}Creating concise, immutable data classes often used for DTOs (Data Transfer Objects) in microservices.
var (Local Variable Type Inference)var list = new ArrayList<String>();Reducing boilerplate code, especially with long generic type names. Only for local variables.

🐛 Common C++ Java Pitfalls

C++ PitfallJava Rule/FixWhy it Happens
Comparing Objects with ==ALWAYS use objectA.equals(objectB) to compare content (e.g., Strings).== compares object references (memory addresses) in Java, not content.
Missing delete keywordJava is Garbage Collected. There is no delete.Manual memory management is replaced by the JVM’s Garbage Collector.
Passing by ReferenceEverything is Pass-by-Value in Java. For objects, the reference itself is passed by value (allowing modification of the original object’s state).Java does not have explicit reference types like & in C++.
NullPointerException (NPE)Check for null or use Optional<T>.Attempting to call a method on a variable that is currently pointing to null.

🌟 Java Best Practices for Backend Development

These practices will help you write “Java-idiomatic” code that is easier for other Java developers (and the JVM) to understand and maintain.


1. Object Equality and Data Handling

PracticeDetails & WhyC++ Context
Always Use .equals()For comparing the content of objects (especially String, wrappers like Integer, or your custom classes), use a.equals(b).Unlike C++ where == can be overloaded for deep comparison, == in Java only compares object references (memory addresses).
Implement hashCode() and equals() TogetherIf you override equals() in a class, you must also override hashCode(). IDEs like IntelliJ or Eclipse can auto-generate these methods.This is critical for correctness when using the object as a key in a HashMap or an element in a HashSet.
Use final for ImmutabilityMake fields final and classes final (if not intended for inheritance) to ensure thread-safety and predictability.Immutability is a cornerstone of thread-safe Microservices and concurrent programming.
Use StringJoiner or String.join()Avoid repetitive string concatenation loops using + or +=.Prefer the efficient StringBuilder for building dynamic strings within loops. String is immutable, so + creates new objects every time.

2. The Collections Framework

PracticeDetails & WhyExplaination
Program to InterfacesDeclare variables using interfaces, not implementation classes.Good: List<String> list = new ArrayList<>(); Bad: ArrayList<String> list = new ArrayList<>(); This makes code more flexible and easier to swap implementations later.
Use GenericsAlways specify the types in angle brackets (e.g., <String>).Prevents runtime ClassCastException errors and provides compile-time type safety. This is similar to C++ templates but with different constraints.
Choose the Right ListFor frequent random access by index, use ArrayList. For frequent insertions/deletions in the middle of the list, use LinkedList.ArrayList is backed by an array; LinkedList uses nodes (better for queue-like operations).

3. Exception Handling

PracticeDetails & WhyC++ Context
Distinguish Checked vs. UncheckedChecked exceptions (e.g., IOException) must be declared (throws) or handled (try/catch). Unchecked (e.g., RuntimeException, NullPointerException) do not.In modern backend development, favor Unchecked Exceptions (e.g., custom exceptions extending RuntimeException) to avoid verbose throws clauses and overly defensive code.
Use try-with-resourcesUse the try (Resource r = ...) syntax for anything that needs closing (e.g., streams, files, database connections). This automatically calls the close() method, preventing resource leaks. This is similar to C++‘s RAII (Resource Acquisition Is Initialization) principle.
Don’t Swallow ExceptionsNever use an empty catch (Exception e) {} block. At a minimum, log the exception.Swallowing exceptions makes debugging nearly impossible, especially in a distributed Microservices environment.

4. Modern Java (Java 8+) and Functional Programming

PracticeDetails & WhyNotes
Prefer Streams Over LoopsUse Java Streams (.stream()) with map, filter, and reduce for collection processing.Streams are more declarative, often lead to cleaner code, and can easily be executed in parallel (.parallelStream()).
Use Optional for Return ValuesUse Optional<T> as the return type for methods that might return “no result” instead of returning null.This forces the caller to explicitly handle the “no result” case, virtually eliminating NullPointerException (NPEs). A common practice in Spring Data repositories.
Embrace Lambda ExpressionsUse lambdas (params) -> { body } instead of anonymous inner classes for functional interfaces.Leads to much more concise, readable, and functional code.

5. OOP and Design

PracticeDetails & WhyNotes
Single Responsibility Principle (SRP)Ensure every class and method has only one reason to change.Leads to small, focused classes which are easier to test, maintain, and integrate into frameworks like Spring Boot.
Prefer Composition Over InheritanceWhere possible, use fields of other classes (composition) instead of the extends keyword (inheritance).Inheritance creates tight coupling. Composition is more flexible and is key to the Dependency Injection patterns used by Spring.
Use Enums for ConstantsUse the enum type instead of public static final int or String fields.Provides type-safe constants, prevents incorrect values, and allows for method definitions within the constant type.

🚀 Java 8 Specific Best Practices

These practices leverage the functional programming features introduced in Java 8 to write more concise, readable, and often more robust code.


1. Functional Interfaces & Lambdas

TipDetails & WhyExample
Use Method ReferencesWhen a lambda simply calls an existing method, use a method reference (::) for ultimate conciseness.Instead of: list.forEach(s -> System.out.println(s)); Use: list.forEach(System.out::println);
Favor Built-in Functional InterfacesStick to standard interfaces (Predicate, Function, Consumer, Supplier) instead of creating your own basic functional interfaces.Predicate<T> for boolean tests, Function<T, R> for mapping, Consumer<T> for side effects (e.g., printing).
Use @FunctionalInterfaceAnnotate your custom interfaces with @FunctionalInterface.It ensures the interface has exactly one abstract method (the definition of a functional interface) and provides a compiler check.

2. Streams API

TipDetails & WhyExample
Avoid Side Effects in Stream OperationsKeep operations like map() and filter() stateless and non-interfering. Don’t modify external data (or the source collection) inside a stream chain.Stream operations are designed for functional purity. Side effects can lead to unpredictable behavior, especially with parallel streams.
Use Primitive Streams Where PossibleUse IntStream, LongStream, and DoubleStream instead of Stream<Integer>, Stream<Long>, etc., when dealing with collections of primitives.Avoids the overhead of autoboxing/unboxing, improving performance and memory usage—crucial for high-throughput backend services.
Prefer Terminal Operations for CollectionUse the highly efficient methods in Collectors (e.g., Collectors.toList(), Collectors.toMap(), Collectors.joining()) to finalize your stream.Avoids manual creation and population of collections, resulting in cleaner code.
Use Collectors.groupingBy()Use this powerful collector to group stream elements, often replacing several lines of manual Map population.Example: people.stream().collect(groupingBy(Person::getCity));

3. Optional<T>

TipDetails & WhyExample
Optional is for Return Types ONLYDo NOT use Optional for method parameters or as fields in domain objects (DTOs/Entities). It defeats the purpose and clutters the code.The purpose is to signal “no result” to the caller, forcing safe handling, not for general state management.
Avoid Optional.get()Calling .get() without first checking isPresent() defeats the entire safety purpose of Optional and can still throw a NoSuchElementException.Instead, use safe alternatives like: .orElse(T), .orElseGet(Supplier), or .orElseThrow().
Use ifPresent() for Side EffectsIf you only want to perform an action if the value is present, use optional.ifPresent(consumer).Example: user.ifPresent(u -> log.info("User found: " + u.getId())); Avoids manual if (user.isPresent()) checks.

4. Date and Time API (java.time)

TipDetails & WhyExample
Use java.time (JSR-310) ExclusivelyDo NOT use the old, flawed classes like java.util.Date, java.util.Calendar, or java.sql.Timestamp.The old APIs were mutable (not thread-safe) and poorly designed. java.time objects are immutable and clearly separate date, time, and timezone.
Distinguish Timezone NeedsUse LocalDate (date only), LocalTime (time only), or LocalDateTime (date + time) when working with values independent of timezone.Use ZonedDateTime or OffsetDateTime when dealing with external systems or users across different time zones.
Use Duration and PeriodUse Duration (time-based) and Period (date-based) for calculating time differences.Example: Duration d = Duration.between(t1, t2); Avoids error-prone manual subtraction of milliseconds.