SLF4j vs Log4j
Java

Java Pair – A Simple Way to Store Two Related Values

Introduction

When working with Java, developers often need to store and pass two related values as a single unit. While many programming languages provide built-in support for tuples or pairs, Java’s standard library does not have a dedicated “Pair” class. This means that developers must rely on third-party libraries or JavaFX’s “Pair” or create their own implementation if they need an easy way to store two related values.

Why do we need a pair in Java?

There are many situations where a “Pair” is useful, for example:

  • Returning multiple values from one method – Java methods can only return a single value, but with a “Pair” we can return two related values.
  • Store key-value mappings – While a “map” is often used for this purpose, sometimes we need a lightweight structure to store a single key-value pair without using a full-fledged map.
  • Graph algorithms and coordinate systems – A “pair” is often used to represent edges in graphs ((node1, node2)) or points in a coordinate system ((x, y)).
  • Caching and lookup tables – Sometimes we need to link two pieces of data together, for example a cache entry with a timestamp or a query with its result.

Why doesn’t Java have a built-in pair?

Unlike other languages like Python (with tuples) or Kotlin (with data classes), Java encourages developers to create well-defined classes instead of using generic structures like Pair. While the use of pairs can be convenient, it sometimes makes code more difficult to read and maintain. For example, a “pair” doesn’t say much about the meaning of the two values, whereas a class like “EmployeeSalary(String Name, int Salary)” is much more meaningful.
In cases where we need a simple, temporary structure to store two related values, a “pair” can be a practical solution. In this blog, we’ll explore different ways to use pairs in Java, including JavaFX’s built-in pair, Apache Commons Lang’s pair, and our own implementations. We will also look at modern alternatives such as Java Records, introduced in Java 14.

What is a Java Pair?

A Pair in Java is a simple data structure that contains two related values as a single unit. It is often used when two values need to be grouped together without creating a separate class. The two values in a Pair are usually referred to as first and second elements.

Definition and concept of a Pair

A Pair is essentially a container object that contains two heterogeneous (different types) or homogeneous (same types) values. It provides methods for retrieving these values and is therefore useful in scenarios where a small, lightweight data structure is required.
For example, imagine a scenario where we need to return both the minimum value and the maximum value from an array. Instead of returning them separately, we can use a Pair to return them together:

Pair minMax = new Pair<>(10, 100);
System.out.println("Min: " + minMax.getKey());
System.out.println("Max: " + minMax.getValue());

Important properties of a Java Pair

  • Stores exactly two values.
  • Can contain different types of values (Pair or Pair).
  • Provides getter methods to access the values (like getKey() and getValue() in Pair of JavaFX).
  • Normally immutable, depending on the implementation.
  • Can be used to return multiple values from a method.
  • Improves readability and simplicity of code when processing two related values.

Common use cases for Pair in Java

Returning multiple values from one method

Java does not directly support multiple return values. A Pair can be used to return two related values:

import javafx.util.Pair;
public class PairExample {
public static Pair findMinMax(int[] numbers) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int num : numbers) {
if (num < min) min = num;
if (num > max) max = num;
}
return new Pair<>(min, max);
}
public static void main(String[] args) {
int[] nums = {5, 1, 9, 7, 3};
Pair result = findMinMax(nums);
System.out.println("Min: " + result.getKey() + ", Max: " + result.getValue());
}
}

Storing Key-Value Pairs

A Pair is useful in cases where we need a simple key-value relationship without using a Map. Example:

Pair productPrice = new Pair<>("Laptop", 75000.00);
System.out.println("Product: " + productPrice.getKey() + ", Price: " + productPrice.getValue());

Displaying a Graph Edge (Node Relationships)

When working with graphs, a Pair can represent an edge between two nodes:

Pair edge = new Pair<>("A", "B");
System.out.println("Edge connects: " + edge.getKey() + " -> " + edge.getValue());

Saving two related values in data structures

A pair is useful in collections such as lists and sets:

List> studentMarks = new ArrayList<>();
studentMarks.add(new Pair<>("Alice", 85));
studentMarks.add(new Pair<>("Bob", 92));

Caching results with a timestamp

A pair can be used in caching scenarios where we store data together with a timestamp:

Pair cacheEntry = new Pair<>("Cached Data", System.currentTimeMillis());

Using JavaFX’s Pair class

JavaFX provides a built-in “Pair” class in the “javafx.util” package, which is one of the easiest ways to use a Pair in Java. With this class, developers can store two related values without having to create a separate class.

Introduction to javafx.util.Pair

The “Pair” class in JavaFX is a simple, generic class that represents a key-value pair. It provides methods to retrieve these values:

  • getKey() – Returns the first element (key).
  • getValue() – Returns the second element (value).

Importing and using JavaFX’s Pair

To use Pair, you need to import it from the JavaFX package:

import javafx.util.Pair;

Here is a simple example of using Pair:

import javafx.util.Pair;
public class PairExample {
public static void main(String[] args) {
// Create a Pair
Pair student = new Pair<>("Alice", 85);
// Retrieve values
System.out.println("Name of the student: " + student.getKey());
System.out.println("Score: " + student.getValue());
}
}

Main features of JavaFX’s Pair

  • Unchangeable values: Once created, the key and value cannot be changed.
  • Easy to use: Provides a straightforward way to store two related values.
  • Limited functionality: Provides only the getKey() and getValue() methods; lacks additional functions such as comparison, modification or serialization.

Example: Returning multiple values from one method

One of the most common uses of Pair is to return multiple values from one method:

import javafx.util.Pair;
public class MinMaxFinder {
public static Pair findMinMax(int[] numbers) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int num : numbers) {
if (num < min) min = num;
if (num > max) max = num;
}
return new Pair<>(min, max);
}
public static void main(String[] args) {
int[] numbers = {3, 8, 1, 5, 9};
Pair result = findMinMax(numbers);
System.out.println("Min: " + result.getKey());
System.out.println("Max: " + result.getValue());
}
}

Example: Storing Key-Value Pairs in a list

The JavaFX class Pair is useful if you want to save several key-value pairs in a list.

import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class PairListExample {
public static void main(String[] args) {
List> products = new ArrayList<>();
// Adding key-value pairs
products.add(new Pair<>("Laptop", 75000.00));
products.add(new Pair<>("Phone", 50000.00));
products.add(new Pair<>("Tablet", 30000.00));
// Iterate through the list
for (Pair product : products) {
System.out.println("Product: " + product.getKey() + ", Price: ₹" + product.getValue());
}
}
}

Limitations of JavaFX’s Pair

Although javafx.util.Pair is easy to use, it has some limitations:

  • Invariant – There is no way to change the values after creation.
  • Limited methods – It only provides getKey() and getValue(), but no additional functions like comparison or serialization.
  • JavaFX dependency – Requires JavaFX, which may not always be available in non-GUI projects.
  • Not widely used – Java developers often prefer third-party libraries (such as Apache Commons Lang) or custom implementations.

When should you use JavaFX Pair?

  • When you need a quick and easy way to store two values.
  • When working within a JavaFX project (since the library is already available).
  • For simple use cases where immutability is not important.

Limitations of JavaFX Pair

While JavaFX javafx.util.Pair provides an easy way to store two related values, it has some limitations that make it less suitable for certain use cases. In this section, we discuss the drawbacks of JavaFX Pair and explain why developers might prefer alternative implementations.

Immutability

One of the main limitations of Pair is that it is immutable — you cannot change its values once it has been created. This means:

  • There are no setter methods to update the “key” or “value”.
  • If you want to change the values, you need to create a new instance of “Pair”.

Example:

import javafx.util.Pair;
public class ImmutablePairExample {
public static void main(String[] args) {
Pair student = new Pair<>("Alice", 85);
// This will not work because Pair does not provide setter methods
// student.setKey("Bob"); // ERROR
// student.setValue(90); // ERROR
// Instead, you have to create a new Pair
student = new Pair<>("Bob", 90);
System.out.println("Updated student: " + student.getKey() + " - " + student.getValue());
}
}

Effect:

  • If your application needs to be changed frequently, using “Pair” can lead to unnecessary objects being created, which increases memory consumption.
  • Alternative approaches such as mutable custom classes or third-party libraries offer more flexibility.

Limited functionality

The JavaFX class “Pair” offers only two methods:

  • getKey()
  • getValue()
    It lacks additional methods that could make it more useful, such as:
  • Comparison (equals() and hashCode() are available, but not customizable).
  • Serialization support (e.g. to convert a “Pair” to JSON).
  • Custom formatting for displaying pairs.

Example:

If you want to format a “Pair” as a readable string, you have to manually override “toString()” in a wrapper class.

import javafx.util.Pair;
public class PairToStringExample {
public static void main(String[] args) {
Pair product = new Pair<>("Laptop", 75000.00);
System.out.println("Product data: (" + product.getKey() + ", " + product.getValue() + ")");
}
}

Effects:

  • You may need to write additional helper methods to work around these limitations.
  • Other libraries, such as Apache Commons Lang, offer more extensive functions.

JavaFX dependency

The class javafx.util.Pair is part of the JavaFX library, which is not included in the standard Java distributions (since Java 11). This means:

  • You can only use Pair if JavaFX is included in your project.
  • If you are not working on a JavaFX application, it does not make sense to add JavaFX only for “Pair”.

Example problem

If you use Pair in a Java project without JavaFX, you may get this error:

Error: Package javafx.util does not exist

Implications:

  • Developers using non-GUI projects must find alternatives such as Apache Commons Lang or own implementations.
  • Additional dependencies can unnecessarily increase the project size.

Not widely used in Java development

Since javafx.util.Pair is part of JavaFX, it is not widely used in enterprise applications or backend systems. Most Java developers prefer third-party libraries such as Apache Commons Lang or Google Guava, which offer more feature-rich alternatives.
Alternative approaches:

  • Apache Commons Lang: Provides Pair, ImmutablePair and MutablePair with extended functionality.
  • Google Guava: Provides ImmutablePair with built-in support for immutability.
  • Custom Pair Class: If you need a lightweight solution without dependencies.

Apache Commons Lang Pair use

The Apache Commons Lang library provides a robust implementation of the “Pair” class that offers more flexibility compared to JavaFX’s “Pair”. It is part of the package “org.apache.commons.lang3.tuple” and includes several variants, such as “Pair”, “ImmutablePair” and “MutablePair”.

Introduction to Apache Commons Lang Pair

The Apache Commons Lang library includes:

  • Pair – A generic abstract class that can be used to define pairs.
  • ImmutablePair – A subclass of Pair that prevents changes.
  • MutablePair – A subclass of Pair that allows values to be changed.
    This implementation provides additional functions such as:
  • Options for mutability and immutability.
  • Customizable serialization and comparison methods.
  • A more intuitive API compared to JavaFX’s Pair.

Add Apache Commons Lang to your project

To use Apache Commons Lang’s Pair, add the following Maven dependency:

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

For Gradle:

dependencies {
implementation 'org.apache.commons:commons-lang3:3.12.0'
}

Once added, you can import and use Pair in your Java application.

Create and use a Pair

The Apache Commons class “Pair” is an abstract class, so you usually use one of its concrete implementations: ImmutablePair or MutablePair.

Example: Creating an immutable Pair

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
public class ImmutablePairExample {
public static void main(String[] args) {
Pair student = new ImmutablePair<>("Alice", 85);
System.out.println("Student: " + student.getLeft());
System.out.println("Score: " + student.getRight());
}
}

Here getLeft() and getRight() are used instead of getKey() and getValue().

Example: Creating a changeable Pair

If you need to change values after creation, use MutablePair:

import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
public class MutablePairExample {
public static void main(String[] args) {
MutablePair student = new MutablePair<>("Alice", 85);
// Change the values
student.setLeft("Bob");
student.setRight(90);
System.out.println("Updated student: " + student.getLeft() + " - " + student.getRight());
}
}

Main features of Apache Commons Pair

Provides both mutable and immutable variants

  • ImmutablePair ensures that values cannot be changed.
  • with MutablePair values can be changed with setLeft() and setRight().

More intuitive naming conventions

Instead of getKey() and getValue() are used:

  • getLeft() – Represents the first element of the pair.
  • getRight() – Represents the second element of the pair.
    This makes it easier to distinguish between key-value pairs and general relationships.

Supports serialization

The Apache Commons Pair implementations implement Serializable, making them suitable for use in distributed systems and file stores.

import org.apache.commons.lang3.tuple.ImmutablePair;
import java.io.*;
public class PairSerializationExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Create an ImmutablePair
ImmutablePair student = new ImmutablePair<>("Alice", 85);
// Serialize the Pair
FileOutputStream fileOut = new FileOutputStream("pair.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(student);
out.close();
fileOut.close();
// Deserialize the Pair
FileInputStream fileIn = new FileInputStream("pair.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
ImmutablePair deserializedStudent = (ImmutablePair) in.readObject();
in.close();
fileIn.close();
System.out.println("Deserialized student: " + deserializedStudent.getLeft() + " - " + deserializedStudent.getRight());
}
}

Supports equals() and hashCode()

The Apache Commons Pair class provides robust implementations of equals() and hashCode(), making it useful for comparisons and collections.
Example:

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.ImmutablePair;
public class PairComparisonExample {
public static void main(String[] args) {
Pair pair1 = new ImmutablePair<>("Alice", 85);
Pair pair2 = new ImmutablePair<>("Alice", 85);
System.out.println("Are the pairs equal? " + pair1.equals(pair2)); // true
}
}

Use cases for Apache Commons Pair

Returning multiple values from one method

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.ImmutablePair;
public class MinMaxExample {
public static Pair findMinMax(int[] numbers) {
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for (int num : numbers) {
if (num < min) min = num;
if (num > max) max = num;
}
return new ImmutablePair<>(min, max);
}
public static void main(String[] args) {
int[] numbers = {3, 8, 1, 5, 9};
Pair result = findMinMax(numbers);
System.out.println("Min: " + result.getLeft() + ", Max: " + result.getRight());
}
}

Storing Key-Value Pairs in a List

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.ArrayList;
import java.util.List;
public class PairListExample {
public static void main(String[] args) {
List> products = new ArrayList<>();
products.add(new ImmutablePair<>("Laptop", 75000.00));
products.add(new ImmutablePair<>("Phone", 50000.00));
products.add(new ImmutablePair<>("Tablet", 30000.00));
for (Pair product : products) {
System.out.println("Product: " + product.getLeft() + ", Price: ₹" + product.getRight());
}
}
}

Creating a custom pair class

Although third-party libraries such as Apache Commons Lang provide a “pair” implementation, sometimes a custom pair class is a better choice. This is especially true if you:

  • Don’t want external dependencies in your project.
  • need additional functionality that goes beyond the standard “Pair” implementations.
  • want better readability by defining meaningful variable names.
    In this section, we’ll learn why and when you should create your own Pair class, followed by a step-by-step implementation.

Why create your own pair class?

Although JavaFX and Apache Commons Lang offer pre-built “pair” implementations, there are good reasons to create your own:

No external dependencies

    • JavaFX’s Pair requires JavaFX, and Apache Commons Lang adds an external library.
    • Having your own Pair keeps your code lean.

    Better readability

      • Instead of using Pair.getLeft() and Pair.getRight(), a custom class allows for meaningful names like Employee.getName() and Employee.getSalary().

      Customization & additional methods

        • You may need additional functions such as data validation, default values or helper methods.

        Performance aspects

          • With a custom class, you can control memory allocation and immutability, avoiding the creation of unnecessary objects.

          Implementation of a basic generic pair class

          A generic “pair” class allows you to store any type of objects together.

          public class Pair {
          private final K key;
          private final V value;
          // constructor
          public Pair(K key, V value) {
          this.key = key;
          this.value = value;
          }
          // Getter
          public K getKey() {
          return key;
          }
          public V getValue() {
          return value;
          }
          // Override toString() for better display
          @Override
          public String toString() {
          return "(" + key + ", " + value + ")";
          }
          }

          Example of use

          public class PairTest {
          public static void main(String[] args) {
          Pair student = new Pair<>("Alice", 85);
          System.out.println("Student: " + student.getKey() + ", Score: " + student.getValue());
          }
          }

          This implementation provides a simple and immutable pair. However, if we need a changeable version, we can customize it accordingly.

          Create a mutable pair class

          If you need to modify values after creation, a modifiable pair can be useful.

          public class MutablePair {
          private K key;
          private V value;
          // constructor
          public MutablePair(K key, V value) {
          this.key = key;
          this.value = value;
          }
          // Getter and setter
          public K getKey() {
          return key;
          }
          public void setKey(K key) {
          this.key = key;
          }
          public V getValue() {
          return value;
          }
          public void setValue(V value) {
          this.value = value;
          }
          @Override
          public String toString() {
          return "(" + key + ", " + value + ")";
          }
          }

          Example of use

          public class MutablePairTest {
          public static void main(String[] args) {
          MutablePair student = new MutablePair<>("Alice", 85);
          // Change the values
          student.setKey("Bob");
          student.setValue(90);
          System.out.println("Updated student: " + student.getKey() + " - " + student.getValue());
          }
          }

          Adding additional functions to Pair

          A custom class “Pair” allows you to add user-defined methods, such as:

          • equality checks
          • Swap values
          • serialization

          Adding equals() and hashCode()

          To make Pair work correctly in HashMaps, Sets and Lists, overwrite equals() and hashCode().

          import java.util.Objects;
          public class Pair {
          private final K key;
          private final V value;
          public Pair(K key, V value) {
          this.key = key;
          this.value = value;
          }
          public K getKey() { return key; }
          public V getValue() { return value; }
          @Override
          public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          Pair pair = (Pair) o;
          return Objects.equals(key, pair.key) && Objects.equals(value, pair.value);
          }
          @Override
          public int hashCode() {
          return Objects.hash(key, value);
          }
          }

          Example of use

          public class PairEqualityTest {
          public static void main(String[] args) {
          Pair p1 = new Pair<>("Alice", 85);
          Pair p2 = new Pair<>("Alice", 85);
          System.out.println("Are the pairs equal? " + p1.equals(p2)); // true
          }
          }

          Adding a swap method

          A swap() method makes it possible to swap key and value.

          public class Pair {
          private final K key;
          private final V value;
          public Pair(K key, V value) {
          this.key = key;
          this.value = value;
          }
          public Pair swap() {
          return new Pair<>(value, key);
          }
          }

          Usage example

          public class PairSwapTest {
          public static void main(String[] args) {
          Pair p = new Pair<>("Alice", 85);
          Pair swapped = p.swap();
          System.out.println("Swapped Pair: " + swapped.getKey() + ", " + swapped.getValue());
          }
          }

          When to use a user-defined Pair class

          A custom “Pair” class is preferable if:

          • You don’t want external dependencies (Apache Commons Lang, JavaFX).
          • You need additional functions (e.g. swap, serialization).
          • You want better readability with meaningful class names.
            However, if you only need a simple key-value structure without additional logic, Pair from Apache Commons Lang is the better choice.

          Java Record as an alternative

          With the introduction of Java Records in Java 14, developers now have a new and efficient way to create immutable data structures. Records are a manageable and readable alternative to Pair, especially when working with small data structures that only contain values.
          In this section we will look at:

          1. What Java Records are
          2. How they can replace “pairs
          3. Advantages of using records
          4. Comparison with other Pair implementations

          What is a Java record?

          A record is a special type of Java class that contains immutable data. Unlike conventional classes, records create data:

          • Automatically generate constructors, getters, equals(), hashCode() and toString().
          • Are immutable, i.e. the values cannot be changed after creation.
          • Improve readability by reducing tinkering code.

          Example: Traditional Java class vs. data set

          Without record (standard Java class)

          public class Employee {
          private final String name;
          private final int Salary;
          public Employee(String name, int salary) {
          this.name = name;
          this.salary = salary;
          }
          public String getName() { return name; }
          public int getSalary() { return Salary; }
          @Override
          public String toString() {
          return "Employee{name='" + name + "', salary=" + salary + "}";
          }
          }

          With record (Java 14+)

          public record Employee(String name, int salary) { }

          In just one line Java creates automatically:

          • Constructor
          • Getter (Name(), Salary())
          • toString()
          • equals()
          • hashCode()

          How Java Records can replace Pair

          Since records are meant for immutable data, they can replace pair“ if you need to store two related values.

          Example: Using a “Pair”

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          public class PairExample {
          public static void main(String[] args) {
          Pair student = new ImmutablePair<>("Alice", 85);
          System.out.println("Student: " + student.getLeft() + ", Score: " + student.getRight());
          }
          }

          Rewrite with Java Record

          public record Student(String name, int score) { }
          public class RecordExample {
          public static void main(String[] args) {
          Student Student = new Student("Alice", 85);
          System.out.println("Student: " + student.name() + ", Score: " + student.score());
          }
          }

          Advantages of using Records compared to Pair:

          • Improved readability (meaningful field names instead of getLeft() and getRight()).
          • No dependency on external libraries like Apache Commons Lang.
          • Less boilerplate code (automatic toString(), equals() and hashCode()).

          Best use cases for data sets

          Java Records are ideal for:

          • returning multiple values from one method
          • Key-value links with meaningful names
          • Immutable data storage (e.g. settings, configurations)
          • Data transfer objects (DTOs) in APIs

          Example: Returning multiple values from one method

          Instead of using “pairs”, we can return a data set:

          public record MinMax(int min, int max) { }
          public class MinMaxExample {
          public static MinMax findMinMax(int[] numbers) {
          int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
          for (int num : numbers) {
          if (num < min) min = num;
          if (num > max) max = num;
          }
          return new MinMax(min, max);
          }
          public static void main(String[] args) {
          int[] numbers = {3, 8, 1, 5, 9};
          MinMax result = findMinMax(numbers);
          System.out.println("Min: " + result.min() + ", Max: " + result.max());
          }
          }

          Additional functions of Java Records

          Adding your own methods

          Even if records automatically generate basic methods, you can still add your own methods.

          public record Product(String name, double price) {
          public String formattedPrice() {
          return "₹" + price;
          }
          }
          public class RecordMethodExample {
          public static void main(String[] args) {
          Product product = new Product("Laptop", 75000.00);
          System.out.println(product.name() + " costs " + product.formattedPrice());
          }
          }

          Comparison: Java Records vs. Pair

          FeatureJava RecordJavaFX PairApache Commons Pair
          ReadabilityExcellent (meaningful names)Poor (generic key values)Poor (generic key values)
          Boilerplate CodeMinimalRequires GetterRequires Getter
          VariabilityImmutableImmutableMutable (MutablePair)
          External dependencyNoRequires JavaFXRequires Apache Commons Lang
          SerializationYes (implements Serializable)NoYes
          Best use casesDTOs, immutable data structures, multiple returnsSmall key-value pairs in JavaFX applicationsGeneral use cases

          When should you use Java Records instead of Pair?

          Use Java Records when:

          You need immutable data storage.
          You want better readability with meaningful field names.
          You want to return several values from one method.
          You want to avoid dependencies on external libraries.

          Use Apache Commons Pair if:

          You need modifiable pairs (MutablePair).
          You are working with older Java versions (before Java 14).
          You need a lightweight solution for the temporary storage of key values.

          Best practices for the use of pairs in Java

          While using pairs can be convenient, it is important to follow best practices to ensure code readability, maintainability and efficiency.
          In this section, we will look at:

          1. When to use a Pair
          2. When to avoid a Pair
          3. readability and maintainability considerations
          4. Performance considerations
          5. Alternatives to Pair

          When is a Pair used?

          The use of a Pair is appropriate in the following situations:
          Returning multiple values from one method

          • When a method must return two related values.
          • Example: A method that returns both the minimum and maximum value of an array.
            Temporary storage of key values
          • If you need to link two values temporarily without creating a separate class.
          • Example: Caching a result with its timestamp.
            Graphical data structures
          • Represents an edge between two nodes.
          • Example: (node1, node2) in a graph algorithm.
            Storing structured data in collections
          • When using lists or sets to store two-part data.
          • Example: A list of student names and grades.

          Example: Using Pair to return multiple values

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          public class MinMaxFinder {
          public static Pair findMinMax(int[] numbers) {
          int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
          for (int num : numbers) {
          if (num < min) min = num;
          if (num > max) max = num;
          }
          return new ImmutablePair<>(min, max);
          }
          public static void main(String[] args) {
          int[] numbers = {3, 8, 1, 5, 9};
          Pair result = findMinMax(numbers);
          System.out.println("Min: " + result.getLeft() + ", Max: " + result.getRight());
          }
          }

          When to avoid using a Pair

          Using a Pair is not always the best option. In some cases it can affect the readability of the code.
          When field names are important

          • If the meaning of Pair.getLeft() and Pair.getRight() is unclear, use a separate class instead.
          • Better alternative: Use a meaningful class like “StudentNote”.
            If the data structure is complex
          • If you need more than two values, consider using a class instead.
            When performance is critical
          • Creating a new instance of “Pair” each time can lead to unnecessary object creation.
          • Use primitive types or arrays when possible.

          Readability and maintainability considerations

          Use a named class instead of a generic Pair

          Using a named class improves the clarity of the code.

          Bad example: Unnecessary use of a Pair

          Pair student = new ImmutablePair<>("Alice", 85);
          System.out.println("Student: " + student.getLeft() + ", Score: " + student.getRight());

          Better example: Using a separate class

          public record StudentScore(String name, int score) { }
          public class RecordExample {
          public static void main(String[] args) {
          StudentScore student = new StudentScore("Alice", 85);
          System.out.println("Student: " + student.name() + ", Score: " + student.score());
          }
          }

          Advantage: The field names name() and score() improve clarity.

          Performance considerations

          The use of pairs can lead to unnecessary object creation. Consider alternatives for better performance.

          Use an array instead of a Pair

          If both values are of the same type, an array may be more efficient.

          public class ArrayExample {
          public static int[] findMinMax(int[] numbers) {
          int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
          for (int num : numbers) {
          if (num < min) min = num;
          if (num > max) max = num;
          }
          return new int[]{min, max};
          }
          public static void main(String[] args) {
          int[] result = findMinMax(new int[]{3, 8, 1, 5, 9});
          System.out.println("Min: " + result [0] + ", Max: " + result [1]);
          }
          }

          Advantage: Reduces object creation and memory consumption.

          Alternatives to Pair

          AlternativeWhen to use
          Java RecordIf you need immutable structured data with meaningful names.
          Custom ClassWhen data needs additional functionality.
          Apache Commons PairWhen you need a fast, generic two-value structure.
          Tuple (from a library like Vavr)When you want to store multiple values in a functional style.
          ArrayIf both elements are of the same type and performance matters.

          Example: Using Vavr’s Tuple instead of Pair

          Vavr is a functional programming library that offers Tuple as an alternative.

          import io.vavr.Tuple;
          import io.vavr.Tuple2;
          public class VavrTupleExample {
          public static void main(String[] args) {
          Tuple2 student = Tuple.of("Alice", 85);
          System.out.println("Student: " + student._1 + ", Score: " + student._2);
          }
          }

          Advantage: Supports tuples with more than two values.

          Use cases and practical examples for Pair object  in Java

          A “Pair” is useful in various programming scenarios where two related values need to be stored together. In this section, we will look at real use cases of “Pair” and how it can be used in practical applications.

          General use cases

          Some of the most common use cases of “Pair” in Java are:

          1. returning multiple values from a method
          2. Key-value associations in data structures
          3. Graph algorithms (edges and relationships)
          4. Mapping of database query results
          5. Saving coordinates in 2D/3D space
          6. Saving results temporarily with timestamps
          7. Display HTTP headers
          8. Linking metadata to data in logging systems

          Return multiple values from one method

          Since Java does not support the direct return of multiple values, a Pair can be used to efficiently return two related values.

          Example: Finding minimum and maximum values in an array

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          public class MinMaxFinder {
          public static Pair findMinMax(int[] numbers) {
          int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
          for (int num : numbers) {
          if (num < min) min = num;
          if (num > max) max = num;
          }
          return new ImmutablePair<>(min, max);
          }
          public static void main(String[] args) {
          int[] numbers = {3, 8, 1, 5, 9};
          Pair result = findMinMax(numbers);
          System.out.println("Min: " + result.getLeft() + ", Max: " + result.getRight());
          }
          }

          Why use a Pair? It allows two related values to be returned without creating a separate class.

          Storing key-value associations in data structures

          Pairs are useful for storing key-value associations in lists without the need for a full Map.

          Example: Saving Student names and grades

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          import java.util.ArrayList;
          import java.util.List;
          public class StudentScores {
          public static void main(String[] args) {
          List> studentScores = new ArrayList<>();
          studentScores.add(new ImmutablePair<>("Alice", 85));
          studentScores.add(new ImmutablePair<>("Bob", 90));
          studentScores.add(new ImmutablePair<>("Charlie", 78));
          for (Pair student : studentScores) {
          System.out.println(student.getLeft() + " scored " + student.getRight());
          }
          }
          }

          Why use a Pair? A “Pair” makes it easy to store related data in collections.

          Graph algorithms (representation of edges)

          In graph algorithms, a “Pair” can be used to represent an edge between two nodes.

          Example: Representation of a graph edge

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          import java.util.ArrayList;
          import java.util.List;
          public class GraphExample {
          public static void main(String[] args) {
          List> edges = new ArrayList<>();
          edges.add(new ImmutablePair<>("A", "B"));
          edges.add(new ImmutablePair<>("B", "C"));
          edges.add(new ImmutablePair<>("C", "D"));
          for (Pair edge : edges) {
          System.out.println("Edge: " + edge.getLeft() + " -> " + edge.getRight());
          }
          }
          }

          Why use a Pair? It provides a clean way to represent relationships in a graph.

          Save coordinates in 2D/3D space

          A “Pair” can store x, y (or even x, y, z with a “triple”).

          Example: Saving 2D coordinates

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          public class CoordinateExample {
          public static void main(String[] args) {
          Pair point = new ImmutablePair<>(10, 20);
          System.out.println("Point: (" + point.getLeft() + ", " + point.getRight() + ")");
          }
          }

          Why use a Pair? It simplifies the handling of x, y coordinates.

          Caching data with timestamps

          A “Pair” can store a value together with its timestamp for caching.

          Example: Caching of API results

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          public class CacheExample {
          public static void main(String[] args) {
          // Store cached data with timestamp
          Pair cachedData = new ImmutablePair<>("weather data", System.currentTimeMillis());
          System.out.println("Cached: " + cachedData.getLeft() + " um " + cachedData.getRight());
          }
          }

          Why use a Pair? It enables the linking of metadata with data.

          Representation of HTTP headers

          A “Pair” can be used to store HTTP headers, which are usually key-value pairs.

          Example: Saving HTTP headers

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          import java.util.ArrayList;
          import java.util.List;
          public class HttpHeadersExample {
          public static void main(String[] args) {
          List> headers = new ArrayList<>();
          headers.add(new ImmutablePair<>("Content-Type", "application/json"));
          headers.add(new ImmutablePair<>("Authorization", "Bearer xyz123"));
          headers.add(new ImmutablePair<>("User-Agent", "Mozilla/5.0"));
          for (Pair header : headers) {
          System.out.println(header.getLeft() + ": " + header.getRight());
          }
          }
          }

          Why use a Pair? It simplifies the management of HTTP headers.

          Associating metadata with data in logging systems

          In logging or monitoring systems, a “Pair” can store a log message together with its log level.

          Example: Logging system

          import org.apache.commons.lang3.tuple.Pair;
          import org.apache.commons.lang3.tuple.ImmutablePair;
          import java.util.ArrayList;
          import java.util.List;
          public class LoggerExample {
          public static void main(String[] args) {
          List> logs = new ArrayList<>();
          logs.add(new ImmutablePair<>("INFO", "Application started"));
          logs.add(new ImmutablePair<>("ERROR", "NullPointerException occurred"));
          logs.add(new ImmutablePair<>("DEBUG", "User authentication successful"));
          for (Pair log : logs) {
          System.out.println("[" + log.getLeft() + "] " + log.getRight());
          }
          }
          }

          Why use a Pair? It efficiently maps the log levels to the log messages.

          Conclusion

          In this blog post, we have looked at Java Pair, its various implementations, use cases, best practices and alternatives. Although Pair is a simple and convenient way to store two related values, its use should be carefully considered in terms of readability, maintainability and performance.

          Key Takeaways

          Here are the key takeaways from our discussion of “Pair” in Java:

          Java does not have a built-in Pair class

            • Unlike other languages (e.g. Python’s “Tuple”, Kotlin’s “Pair”), Java does not provide a default implementation of Pair.
            • Developers must use third party libraries (such as Apache Commons Lang) or create their own Pair class.

            JavaFX’s Pair is limited

              • Found in javafx.util.Pair, but requires JavaFX.
              • it is immutable and has no features like serialization or mutability.

              The Pair from Apache Commons Lang `is more powerful

                • Provides ImmutablePair and MutablePair.
                • Supports serialization, hashing and comparison.
                • Recommended for most general use cases.

                Creating a custom “Pair” class offers flexibility

                  • Avoids dependencies and allows own methods such as swap(), equals() and hashCode().
                  • Provides better readability when Pair.getLeft() and Pair.getRight() are unclear.

                  Java Records (Java 14+) offer a modern alternative

                    • Ideal for immutable key-value associations with meaningful field names.
                    • Generates constructors, getters, toString(), equals() and hashCode() automatically.

                    Best practices for the use of Pair

                      • Use Pair for temporal associations or returning multiple values.
                      • Avoid Pair if a own class would provide more clarity.
                      • Consider performance and memory usage when choosing between Pair, arrays or records.

                      Common practical applications of Pair

                        • Return multiple values from one method (e.g. min/max in an array).
                        • Graph algorithms (representation of edges between nodes).
                        • Store key value data (e.g. student names and grades).
                        • Manage HTTP headers, logs and caching with metadata.

                        Choosing the right approach

                        When deciding whether to use a “Pair”, you should consider the best alternative for your use case:

                        ScenarioRecommended approach
                        Return two values from one methodPair or Java Record
                        Immutable storage of key valuesJava Record
                        Temporary storage in a listPair
                        Mutable key value pairMutablePair (Apache Commons)
                        More than two valuesUse a custom class or Tuple
                        Readability and maintainabilityUse a custom class
                        Performance optimizationUse arrays if the values are of the same type

                        When should you use Java pairs?

                        Use caseUse Pair?Better alternative?
                        Temporary storage of key valuesYes
                        Returning multiple valuesYesJava Record (if immutable)
                        Graph algorithms (edges)Yes
                        Complex objects with more than two fieldsNoUser-defined class
                        Serialization & StorageYesApache Commons Pair
                        Readability is a priorityNoUser-defined class or Java Record

                        Final thoughts

                        Since Java does not have a built-in “Pair”, developers must carefully choose the best approach based on readability, performance and maintainability.

                        • If you need a temporary key-value store, Pair is a fast and easy solution.
                        • If you need immutability with better readability, Java Records are the best choice.
                        • If you need a robust, universal solution, Apache Commons Lang Pair is recommended.
                        • If you need extensibility and clarity, creating a custom class is often the best practice.
                          Understanding the advantages and disadvantages of each approach will help you write cleaner, more maintainable and efficient Java code.