How to create custom Tuple in Java

In this article, I will show you to create a simple custom Tuple class and how to use that in java classes.

Tools Used :

1) eclipse version Luna 4.4.1.
2) Maven
3) JDK 1.8

When to Use?
The initial motivation is to use this tuple object as Key in HashMap.

Simple Steps to be followed

1) Create a Maven project.

2) Modify the pom.xml file.

3) Create a Tuple class.

4) Tweak App.java class to create and use the Tuple class.

2) Modify the pom.xml file:
After maven project is created in eclipse, add all required dependencies.
Here is the complete pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.devjavasource.concurrency</groupId>
	<artifactId>tuples</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>tuples</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>		
		<jdk.version>1.8</jdk.version>
	</properties>

	<dependencies>	
		<!-- https://mvnrepository.com/artifact/net.jcip/jcip-annotations -->
		<dependency>
			<groupId>net.jcip</groupId>
			<artifactId>jcip-annotations</artifactId>
			<version>1.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>r05</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.jetbrains/annotations -->
		<dependency>
			<groupId>org.jetbrains</groupId>
			<artifactId>annotations</artifactId>
			<version>13.0</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- Set a compiler level -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>${jdk.version}</source>
					<target>${jdk.version}</target>
				</configuration>
			</plugin>

			<!-- Maven Assembly Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-assembly-plugin</artifactId>
				<version>2.4.1</version>
				<configuration>
					<!-- get all project dependencies -->
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
					<!-- MainClass in mainfest make a executable jar -->
					<archive>
						<manifest>
							<mainClass>com.devjavasource.concurrency.tuples.App</mainClass>
						</manifest>
					</archive>
				</configuration>
				<executions>
					<execution>
						<id>make-assembly</id>
						<!-- bind to the packaging phase -->
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

		</plugins>
	</build>
</project>

3) Create a Tuple class:
This is pretty simple, Create a class with name Tuple that implements Serializable interface
and add a private constructor to restrict object creation from outside the class.
Tuple.java

package com.devjavasource.concurrency.tuples;

import java.io.Serializable;

import org.jetbrains.annotations.NotNull;
import com.google.common.base.Preconditions;

import net.jcip.annotations.ThreadSafe;

/**
 * An immutable, serializable 2-tuple class.
 * this can be used as Key in Hash maps.
 * 
 * @author devjavasource.
 *
 * @param <A>
 * @param <B>
 */
@ThreadSafe
public class Tuple<A extends Serializable, B extends Serializable> implements Serializable{

	private static final long serialVersionUID = 42L;
	private A _first;
	private B _second;
	
	private Tuple(@NotNull final A inA, @NotNull final B inB){
		_first = inA;
		_second = inB;
	}
	
	/**
	 * Create a Factory to initialize
	 * @param inA first Tuple
	 * @param inB second Tuple
	 * @return tuple
	 */
	public static <A extends Serializable, B extends Serializable> Tuple<A, B> create(@NotNull final A inA, @NotNull final B inB) {
		Preconditions.checkNotNull(inA, "Null not accepted for first argument");
		Preconditions.checkNotNull(inB, "Null not accepted for second argument");
		return new Tuple<>(inA, inB);
	}

	@Override	
	public boolean equals(Object inObject) {
		if(this == inObject) return true;
		
		if(inObject == null || getClass() != inObject.getClass())
			return false;		
		
		Tuple<?, ?> tuple = (Tuple<?, ?>) inObject;
		
		if(!getFirst().equals(tuple.getFirst()))
			return false;
		
		if(!getSecond().equals(tuple.getSecond()))
			return false;
		
		return true;
	}
	
	@Override
	public int hashCode() {
		int result = getFirst().hashCode();
		result = 31 * result + getSecond().hashCode();
		return result;
	}
	
	@Override
	public String toString() {
		return "Tuple{_first=" + getFirst() + ", _second=" + getSecond() + "}";
	}
	@NotNull
	public A getFirst() {
		return _first;
	}
	
	@NotNull
	public B getSecond() {
		return _second;
	}
	
	@NotNull
	public String asCompoundKeyString() {
		return _first.toString() + _second.toString();
	}
}

4) Demo:
Tweak App.java class to create and use the Tuple class.
App.java

package com.devjavasource.concurrency.tuples;

import java.util.HashMap;
import java.util.Map;

/**
 * This class is to test created Tuple.
 *
 */
public class App {
	public static void main( String[] args )
    {
        Tuple<String, String> tuple = Tuple.create("first argument", "second argument");
        
        System.out.println( "First Arument is: " + tuple.getFirst() );
        System.out.println( "Second Arument is: " + tuple.getFirst() );
        
        Map<Tuple<String, String>, String> map = new HashMap<>();
        map.put(tuple, "valueInMap");
        
        System.out.println("Value in Map is: " + map.get(tuple));
        
        Tuple<Emp, Emp> empTuple = Tuple.create(new Emp("1", "One"), new Emp("2", "Two"));
        
        System.out.println(empTuple.getFirst().toString());
        System.out.println(empTuple.getSecond().toString());
    }
}

Select the class and click on “Run As” -> “Java Application”.
Out Put :

First Arument is: first argument
Second Arument is: first argument
Value in Map is: valueInMap
Emp [empNo=1, empName=One]
Emp [empNo=2, empName=Two]

You can download the complete project, Here
Download Source: tuples

1) Download and un-zip, Run > mvn package command to package the project.
2) Go to the path up to dist folder and run > java -jar tuples-0.0.1-SNAPSHOT-jar-with-dependencies.jar

Github link is Here,
tuples github link
*** Venkat – Happy learning ****