(See also the continuation of this post.)
This time, I have a mapping type:
com.github.coderodde.mapping.Mapping.java:
package com.github.coderodde.mapping;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* This class implements a mapping from a domain set to a range set.
*
* @param <D> the domain element type.
* @param <R> the range element type.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Sep 3, 2023)
* @since 1.6 (Sep 3, 2023)
*/
public final class Mapping<D, R> {
final Map<D, R> data = new HashMap<>();
public void map(D domainValue, R rangeValue) {
checkDomainValueNotYetMapped(domainValue);
data.put(domainValue, rangeValue);
}
public boolean isMapped(D domainValue) {
return data.containsKey(
Objects.requireNonNull(
domainValue,
"The input domain value is null."));
}
public R map(D domainValue) {
checkDomainValueIsMapped(domainValue);
return data.get(domainValue);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
boolean first = true;
for (Map.Entry<D, R> entry : data.entrySet()) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append("(")
.append(entry.getKey())
.append(", ")
.append(entry.getValue())
.append(")");
}
sb.append("]");
return sb.toString();
}
private void checkDomainValueNotYetMapped(D domainValue) {
if (data.containsKey(
Objects.requireNonNull(domainValue, "Domain value is null."))) {
throw new DuplicateDomainValueException(
"Trying to map a domain value ["
+ domainValue
+ "] twice.");
}
}
private void checkDomainValueIsMapped(D domainValue) {
if (!data.containsKey(domainValue)) {
throw new DomainValueIsNotMappedException(
"Domain value [" + domainValue + "] is not mapped.");
}
}
}
Also, I can compose mappings:
com.github.coderodde.mapping.MappingComposition.java:
package com.github.coderodde.mapping;
import java.util.Map;
/**
* This class provides facilities for composing mappings.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Sep 3, 2023)
* @since 1.6 (Sep 3, 2023)
*/
public final class MappingComposition {
/**
* Composes two functions together. For example, if
* {@code mapping1 = [(1, 'a'], (2, 'b'), (3, 'c')]} and
* {@code mapping2 = [('a', "Alice"), ('c', "Clarice")]}, then the composed
* mapping is {@code [(1, "Alice"), (3, "Clarice")]}.
*
* @param <D> the domain value type of the first mapping.
* @param <T> the domain value type of the second mapping. This is the same
* as the range value type of the first mapping.
* @param <R> the range value type of the second mapping.
* @param mapping1 the first mapping.
* @param mapping2 the second mapping.
* @return a composed function.
*/
public static <D, T, R> Mapping<D, R> compose(Mapping<D, T> mapping1,
Mapping<T, R> mapping2) {
Mapping<D, R> result = new Mapping<>();
for (Map.Entry<D, T> entry1 : mapping1.data.entrySet()) {
D domainValue = entry1.getKey();
T temporaryValue = entry1.getValue();
if (mapping2.isMapped(temporaryValue)) {
R rangeValue = mapping2.map(temporaryValue);
result.map(domainValue, rangeValue);
}
}
return result;
}
}
... I need some exception definitions:
package com.github.coderodde.mapping;
/**
* Instances of this class are thrown on occasions where the domain value is not
* yet mapped to a range value.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Sep 3, 2023)
* @since 1.6 (Sep 3, 2023)
*/
public final class DomainValueIsNotMappedException extends RuntimeException {
public DomainValueIsNotMappedException(String exceptionMessage) {
super(exceptionMessage);
}
}
package com.github.coderodde.mapping;
/**
* Instances of this class are thrown on occasions where the domain value is
* already mapped and we are trying to map it to a second range value.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Sep 3, 2023)
* @since 1.6 (Sep 3, 2023)
*/
public final class DuplicateDomainValueException extends RuntimeException {
public DuplicateDomainValueException(String exceptionMessage) {
super(exceptionMessage);
}
}
Finally, the demonstration program follows:
package com.github.coderodde.mapping;
class MappingCompositionDemo {
public static void main(String[] args) {
mapDual();
mapFour();
}
private static void mapDual() {
Mapping<Character, Integer> mapping1 = new Mapping<>();
Mapping<Integer, String> mapping2 = new Mapping<>();
mapping1.map('a', 1);
mapping1.map('b', 2);
mapping1.map('c', 3);
mapping2.map(1, "Alice");
mapping2.map(2, "Clarice");
System.out.println(MappingComposition.compose(mapping1, mapping2));
}
private static void mapFour() {
Mapping<Character, Integer> mapping1 = new Mapping<>();
Mapping<Integer, String> mapping2 = new Mapping<>();
Mapping<String, Long> mapping3 = new Mapping<>();
Mapping<Long, Float> mapping4 = new Mapping<>();
mapping1.map('a', 1);
mapping1.map('b', 2);
mapping1.map('c', 3);
mapping2.map(1, "Alice");
mapping2.map(3, "Clarice");
mapping3.map("Alice", 11L);
mapping3.map("Bob", 12L);
mapping3.map("Clarice", 13L);
mapping4.map(11L, 11.0f);
mapping4.map(12L, 12.0f);
mapping4.map(13L, 13.0f);
System.out.println(
MappingComposition.compose(
MappingComposition.compose(mapping1, mapping2),
MappingComposition.compose(mapping3, mapping4)));
}
}
Demo output
[(a, Alice), (b, Clarice)]
[(a, 11.0), (c, 13.0)]
Critique request
As always, I would like to hear whatever comes to mind.