Edit: To be clear I am not asking how to do enums in java. I am asking if there is something in java that is complementary to Swifts associated values in enums. This is not just simply how do I store values on enums. Take a look at the example I provided and you will see the difference.
So an iOS developer was showing me an architecture where he used swifts enum associated values. This concept seemed interesting to me I and as an android developer I was curious to see if its possible in java without being overly verbose. What is the equivalent with Java enums? Or is it not possible?
Here is an example of what I mean by Associated Values. Its pulled form the apple docs.
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
// Instantiated
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
// or
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
println("QR code: \(productCode).")
}
For instance, you might describe a weather enum that lists sunny, windy, and rainy as cases, but has an associated value for cloudy so that you can store the cloud coverage. Or you might describe types of houses, with the number of bedrooms being an associated integer.
You cannot create an object of an enum explicitly so, you need to add a parameterized constructor to initialize the value(s). The initialization should be done only once. Therefore, the constructor must be declared private or default. To returns the values of the constants using an instance method(getter).
An enum cannot have both raw values and associated values at the same time. The raw values of an enum must be of the same data type. But associated values can be of any type.
The Problem with Associated Values We had to do this because Swift doesn't allow us to have both: raw values and associated values within the same enum. A Swift enum can either have raw values or associated values.
For me with Java enums this will not be possible.
To be close to your posted snippet you would be verbose, as you already assume.
enum
enum BarcodeType {
UPCA,
QRCode,
UNDEFINED;
}
factory class
abstract class Barcode {
abstract public BarcodeType getType();
public static final Barcode newUPCA(int numberSystem, int manufacturer, int product, int check) {
return new BarcodeUPCA(numberSystem, manufacturer, product, check);
}
public static final Barcode newQRCode(String productCode) {
return new BarcodeQRCode(productCode);
}
}
concrete implementation UPCA
class BarcodeUPCA extends Barcode {
private final int numberSystem;
private final int manufacturer;
private final int product;
private final int check;
public BarcodeUPCA(int numberSystem, int manufacturer, int product, int check) {
this.numberSystem = numberSystem;
this.manufacturer = manufacturer;
this.product = product;
this.check = check;
}
public int getNumberSystem() {
return numberSystem;
}
public int getManufacturer() {
return manufacturer;
}
public int getProduct() {
return product;
}
public int getCheck() {
return check;
}
@Override
public BarcodeType getType() {
return BarcodeType.UPCA;
}
}
concrete implementation QRCode
class BarcodeQRCode extends Barcode {
private final String productCode;
public BarcodeQRCode(String productCode) {
this.productCode = productCode;
}
public String getProductCode() {
return productCode;
}
@Override
public BarcodeType getType() {
return BarcodeType.QRCode;
}
}
demo application
public class BarcodeMain {
public static void main(String[] args) throws Exception {
List<Barcode> barcodes = new ArrayList<>();
barcodes.add(Barcode.newUPCA(8, 85909, 51226, 3));
barcodes.add(Barcode.newQRCode("foobar"));
for (Barcode barcode : barcodes) {
switch (barcode.getType()) {
case UPCA: {
BarcodeUPCA b = (BarcodeUPCA) barcode;
System.out.printf("UPC-A: %d, %d, %d, %d%n",
b.getNumberSystem(),
b.getManufacturer(),
b.getProduct(),
b.getCheck()
);
break;
}
case QRCode: {
BarcodeQRCode b = (BarcodeQRCode) barcode;
System.out.printf("QR code: %s%n", b.getProductCode());
break;
}
default:
System.err.println("unhandled type: " + barcode.getType());
}
}
}
output
UPC-A: 8, 85909, 51226, 3
QR code: foobar
I also struggled with this question, and came up with the following solution. Notably, I don't even use enums, since Java's enums are not well-suited to the task. The important part is that you need switch
-like behaviour for the cases, with the associated values available in each case.
enum-like type
public abstract class Barcode
{
private Barcode() {}
void caseUPCA(IntFunction<IntFunction<IntFunction<IntConsumer>>> action) {}
void caseQRCode(Consumer<String> action) {}
static Barcode UPCA(int numberSystem, int manufacturer, int product, int check)
{
return new Barcode()
{
@Override public void caseUPCA(IntFunction<IntFunction<IntFunction<IntConsumer>>> action)
{
action.apply(numberSystem).apply(manufacturer).apply(product).accept(check);
}
};
}
static Barcode QRCode(String text)
{
return new Barcode()
{
@Override public void caseQRCode(Consumer<String> action)
{
action.accept(text);
}
};
}
}
demo application
public class BarcodeMain
{
public static void main(String[] args) throws Exception
{
List<Barcode> barcodes = new ArrayList<>();
barcodes.add(Barcode.UPCA(8, 85909, 51226, 3));
barcodes.add(Barcode.QRCode("foobar"));
for(Barcode barcode: barcodes)
{
barcode.caseUPCA(numberSystem -> manufacturer -> product -> check ->
System.out.printf("UPC-A: %d, %d, %d, %d%n", numberSystem, manufacturer, product, check));
barcode.caseQRCode(productCode ->
System.out.printf("QR code: %s%n", productCode));
}
}
}
output
UPC-A: 8, 85909, 51226, 3
QR code: foobar
pros
cons
Barcode
implementation. Just Java being ugly.UPCA
implementation, due to having many arguments. To prevent this leaking into the API, you could declare a public interface UPCAConsumer extends IntFunction<IntFunction<IntFunction<IntConsumer>>> {}
, and use UPCAConsumer
for the caseUPCA(action)
argument type.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With