简体   繁体   中英

Expressing anonymous intersection types in Java

None of these compile but ... I would like to express anonymous intersection types in Java such that (A & B) means any type that implements/extends both A and B interfaces, but expressed anonymously in code by composing the types with some syntax like & . In particular I'd like to use them in the following circumstances:

  1. method parameters eg public void foo((A & B) x) { ... }
  2. method return types eg public (A & B) foo() { ... }
  3. local variables eg (A & B) foo = ...
  4. wildcard generics eg List<? extends A & B)> foo = ... List<? extends A & B)> foo = ...

Am I right in thinking that the options for me as of now (Java 13) are as follows?

  1. method parameters - use generics: public static <T extends A & B> void foo(T x) { ... }
  2. method return types - use generics: public static <T extends A & B> T foo() { ... }
  3. local variables - use var var foo = (A & B) bar
  4. wildcard generics - no current option

The following articles dig deeper into when/why these types can be useful. This article nicely covers 1. This article covers 1. 2. and 3. This SO question covers 4. and how curious it is that Java has no syntax for this.

--- edited to explain my use case as requested ---

I often use Value objects holding only items of information. These information items are relatively re-usable independently but are often just globbed together for convenience and passed around other classes that apply actual logic with them. I find it's very easy to name getter interfaces in a way that's stable and reusable long term. There's very little debate about what getCustomerForename() and getCustomerId() will return, and defining these is close to defining a "data model" for your business. But once you try and bolt them together to make say a Customer interface, that interface often becomes very special purpose and innappropriately reused as in some contexts you need all the customer info, where in others you only need a few, or with other pieces of data mixed in. It's hard to name, creates coupling whether needn't be any and creates extra code. Instead I want to avoid creating/naming any new interfaces and instead use an anonymous intersection type creating a new type on the fly from existing ones that expose just one getter at a time. So the interfaces A and B in the above would be interfaces such as the following:

interface CustomerId {
  Long getCustomerId();
}

interface CustomerForename {
  String getCustomerForename();
}

... and if I had a report that just surfaced those 2 items, I'd just create objects with the "type" (CustomerId & CustomerForename) instead of naming and creating a CustomerIdAndCustomerForename interface/class for very little benefit.

If you have a type parameter specified as <T extends A&B> you can use it in wildcard types as is done in the following example using Optional<? extends T> Optional<? extends T> . Which is similar, but I guess not the same as what you want to do, although right now my brain hurts too much to explain what the difference is.


public class GenericsTest {

    public static void main(String[] args) {

        System.out.println(generateCombination().get().getB());
        System.out.println(generateCombination().get().getA());
    }

    static <T extends A&B> Optional<? extends T> generateCombination() {
        return (Optional<? extends T>) Optional.of(new Both());
    }

     interface A {
        String getA();
    }

     interface B {
        Number getB();
    }

    static class Both implements A, B {
        @Override
        public String getA() {
            return "Hello";
        }

        @Override
        public Number getB() {
            return 23;
        }
    }
}

Anyway the other variants seem to be correct as described in your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM