I'm getting a compilation warning: "ExampleConsumer.java uses unchecked or unsafe operations." on line return example.distance(other);. How do I properly check the type? Obviously I need to enforce that the types are the same.
Here's my code:
Example.java
public abstract class Example<T, U> {
public T t;
public U u;
public Example(T t, U u) {
this.t = t;
this.u = u;
}
abstract double distance(Example<T, U> other);
}
SpecialExample.java
public class SpecialExample extends Example<Integer, Double> {
public SpecialExample(Integer i, Double d) {
super(i, d);
}
#Override
double distance(Example<Integer, Double> other) {
return (double)(t - other.t) + u * other.u;
}
}
BadExample.java
public class BadExample extends Example<String, String> {
public BadExample(String s1, String s2) {
super(s1, s2);
}
#Override
double distance(Example<String, String> other) {
return (double)(t.length() + other.t.length()) + (u.length() * other.u.length());
}
}
ExampleConsumer.java
public class ExampleConsumer<E extends Example> {
private E example;
public ExampleConsumer(E example) {
this.example = example;
}
public double combine(E other) {
return example.distance(other);
}
}
Main.java
class Main {
public static void main(String[] args) {
SpecialExample special = new SpecialExample(1, 2.0);
ExampleConsumer<SpecialExample> consumer = new ExampleConsumer<>(special);
BadExample bad = new BadExample("foo", "bar");
consumer.combine(special); // compiles with warning
// consumer.combine(bad); // doesn't compile = good!
}
}
Here's one solution:
ExampleConsumer.java
public class ExampleConsumer<A, B, E extends Example<A, B>> {
private E example;
public ExampleConsumer(E example) {
this.example = example;
}
public double combine(E other) {
return example.distance(other);
}
}
Main.java
class Main {
public static void main(String[] args) {
// ...
ExampleConsumer<Integer, Double, SpecialExample> consumer = new ExampleConsumer<>(special);
// ...
}
}
But I'd rather not have to repeat the Double/Integer types in Main.java :/
Related
In the jdk8u source code for the ReduceOps class, lines 155-190 (reproduced below) constitute the makeRef method:
public static <T, I> TerminalOp<T, I>
makeRef(Collector<? super T, I, ?> collector) {
Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
BiConsumer<I, ? super T> accumulator = collector.accumulator();
BinaryOperator<I> combiner = collector.combiner();
class ReducingSink extends Box<I>
implements AccumulatingSink<T, I, ReducingSink> {
#Override
public void begin(long size) {
state = supplier.get();
}
#Override
public void accept(T t) {
accumulator.accept(state, t);
}
#Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
#Override
public ReducingSink makeSink() {
return new ReducingSink();
}
#Override
public int getOpFlags() {
return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
? StreamOpFlag.NOT_ORDERED
: 0;
}
};
}
I am asking explicitly about lines 177-189:
return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
#Override
public ReducingSink makeSink() {
return new ReducingSink();
}
#Override
public int getOpFlags() {
return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
? StreamOpFlag.NOT_ORDERED
: 0;
}
};
What does the code after the return statement do (and why is it not unreachable)? I'm guessing it's doing something like overriding some methods from an interface called ReduceOp, but it appears that such an interface (if it exists) is not in the same place as many of the other relevant interfaces.
I have a generic class with a generic list in it. I want to ensure that the generic list only contains unique classes.
What I have done so far is to compare the class names with reflection (getClass()). But I think that's not a clean solution. Are there any better practices to check?
public class MyGenericClass<T extends MyGenericClass.MyInterface> {
private List<T> members = new ArrayList<>(0);
public void add(T t) {
final boolean[] classInMembers = {false};
members.forEach(member -> {
if (member.getClass().getName().equals(t.getClass().getName())) {
classInMembers[0] = true;
}
});
if (!classInMembers[0]) {
members.add(t);
}
}
public interface MyInterface {
void doSomething(String text);
}
}
public class Main {
public static void main(String[] args) {
MyGenericClass<MyGenericClass.MyInterface> myGenericClass = new MyGenericClass<>();
myGenericClass.add(new Performer1());
myGenericClass.add(new Performer2());
myGenericClass.add(new Performer3());
myGenericClass.add(new Performer3()); // should not be inserted!
}
private static class Performer1 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 1!";
}
}
private static class Performer2 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 2!";
}
}
private static class Performer3 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 3!";
}
}
}
You could subclass a java.util.Set interface implementation. It will likely be easiest to subclass java.util.AbstractSet.
By default 'Set' will compare objects by their .equals() method - In your case, this is not sufficient. You will need to override the contains method to ensure that only instances of a unique class are added.
In your overrideen contains, it's probably the same / easier to compare class instances rather than their stringified package name
I.e. use a.getClass() == b.getClass(), rather than a.getClass().getName()
Don't use a List, use a java.util.Set instead.
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.
If the iteration order is important or if you want to use a custom Comparator, the TreeSet implementation can be used:
A NavigableSet implementation based on a TreeMap. The elements are ordered using their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used.
Example of a Set using a Comparator:
class MyComparator implements Comparator<Object> {
#Override
public int compare(Object e1, Object e2) {
if (e1.getClass() == e2.getClass())
return 0;
//if you wish to have some extra sort order
return e1.getClass().getName().compareTo(e2.getClass().getName());
}
}
. . .
Set mySet = new TreeSet<Object>(new MyComparator());
mySet.add(new Object());
mySet.add(new Object());//same class already in set
mySet.add("wtf");
//mySet.size() is now 2 - the second "new Object()" was not inserted due to the comparator check
Why so complicated?
public class Main {
public static void main(String[] args) {
final Class<?> helloClass = "Hello".getClass();
final Class<?> worldClass = "World".getClass();
final Class<?> intClass = Integer.class;
System.out.println(helloClass.equals(worldClass)); // -> true
System.out.println(helloClass.equals(intClass)); // -> false
}
}
You could maintain a roster of members in a Set.
public static class MyGenericClass<T extends MyGenericClass.MyInterface> {
private List<T> members = new ArrayList<>(0);
// Add this.
private Set<Class<?>> roster = new HashSet<>();
public void add(T t) {
if (!roster.contains(t.getClass())) {
members.add(t);
roster.add(t.getClass());
}
}
private void soundOff() {
for (T t : members) {
t.doSomething();
}
}
public interface MyInterface {
void doSomething();
}
}
private static class Performer implements MyGenericClass.MyInterface {
final int n;
public Performer(int n) {
this.n = n;
}
#Override
public void doSomething() {
System.out.println("Hi, I am a " + this.getClass().getSimpleName() + "(" + n + ")");
}
}
private static class Performer1 extends Performer {
public Performer1(int n) {
super(n);
}
}
private static class Performer2 extends Performer {
public Performer2(int n) {
super(n);
}
}
private static class Performer3 extends Performer {
public Performer3(int n) {
super(n);
}
}
public void test() {
MyGenericClass<MyGenericClass.MyInterface> myGenericClass = new MyGenericClass<>();
myGenericClass.add(new Performer1(1));
myGenericClass.add(new Performer2(2));
myGenericClass.add(new Performer3(3));
myGenericClass.add(new Performer3(4)); // should not be inserted!
myGenericClass.soundOff();
}
You could implement a Wrapper which provides the necessary comparison and add the wrapped instance to the set. This way you don't have to override equals and hashcode in your concrete Performer classes and you don't have to subclass a concrete Set implementation (which you are coupled to. When you subclass a HashSet, you have to use that concrete class. But what if you want to use a LinkedHashSet at some point? You have to override LinkedHashSet as well) , which may be fragile since you have to make sure that the overridden method is consistent with the rest of the class.
class MyGenericClass<T extends MyInterface> {
private Set<ClassCompareWrapper<T>> members = new HashSet<>();
public void add(T t) {
members.add(new ClassCompareWrapper<T>(t));
}
}
class ClassCompareWrapper<T> {
T t;
public ClassCompareWrapper(T t) {
this.t = t;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof ClassCompareWrapper))
return false;
ClassCompareWrapper<?> that = (ClassCompareWrapper<?>) o;
return Objects.equals(t.getClass(), that.t.getClass());
}
#Override
public int hashCode() {
return Objects.hash(t.getClass());
}
#Override
public String toString() {
return "Wrapper{" +
"t=" + t +
'}';
}
}
Here are a few other ideas.
Using streams:
public void add(T t) {
if (!members.stream().anyMatch(m -> m.getClass() == t.getClass())) {
members.add(t);
}
}
Using AbstractSet and HashMap:
class ClassSet<E> extends AbstractSet<E> {
private final Map<Class<?>, E> map = new HashMap<>();
#Override
public boolean add(E e) {
// this can be
// return map.putIfAbsent(e.getClass(), e) != null;
// in Java 8
Class<?> clazz = e.getClass();
if (map.containsKey(clazz)) {
return false;
} else {
map.put(clazz, e);
return true;
}
}
#Override
public boolean remove(Object o) {
return map.remove(o.getClass()) != null;
}
#Override
public boolean contains(Object o) {
return map.containsKey(o.getClass());
}
#Override
public int size() {
return map.size();
}
#Override
public Iterator<E> iterator() {
return map.values().iterator();
}
}
A HashMap could also be used without wrapping it in a Set. The Set interface is defined around equals and hashCode, so any implementation which deviates from this is technically non-contractual. Additionally, you might want to use LinkedHashMap if the values are iterated often.
To be precise, I am trying to flatten a tree and I am stuck on trying to get the values of private attributes in a generic class using a generic function.
I have attached the classes to show how the tree is structured exactly. But it's looks something like this:
/|\
1 | 6
/|\
5 4 9
I am going to paste my attempt at the end. First, let me introduce the classes:
Triple simply stores three values of the same type.
public class Triple<V> {
private final V l, m, r;
public Triple(V l, V m, V r) {
this.l = l;
this.m = m;
this.r = r;
}
public V left() { return l; }
public V middle() { return m; }
public V right() { return r; }
}
Straightforward interface:
public interface Function<P, R> {
R apply(P p);
}
Now, for a tricky class. This one is simply a type that stores one of EitherOr of two types of value, but not both.
public class EitherOr<A,B> {
// Constructs a left-type EitherOr
public static <A> EitherOr left(A a) {
return new EitherOr(a, null);
}
// Constructs a right-type EitherOr
public static <B> EitherOr right(B b) {
return new EitherOr(null, b);
}
private final A a;
private final B b;
private EitherOr(A a, B b) {
this.a = a; this.b = b;
}
public<T> T ifLeft(Function<A,T> f) {
return f.apply(a);
}
public<T> T ifRight(Function<B,T> f) {
return f.apply(b);
}
public boolean isLeft() {
return b == null;
}
}
I know this is getting long, but bear with me. This class implements the tree structure.
public interface Tree<T> {
EitherOr<T, Triple<Tree<T>>> get();
static final class Leaf<T> implements Tree<T> {
public static <T> Leaf<T> leaf (T value) {
return new Leaf<T>(value);
}
private final T t;
public Leaf(T t) { this.t = t; }
#Override
public EitherOr<T, Triple<Tree<T>>> get() {
return EitherOr.left(t);
}
}
static final class Node<T> implements Tree<T> {
public static <T> Tree<T> tree (T left, T middle, T right) {
return new Node<T>(Leaf.leaf(left), Leaf.leaf(middle), Leaf.leaf(right));
}
private final Triple<Tree<T>> branches;
public Node(Tree<T> left, Tree<T> middle, Tree<T> right) {
this.branches = new Triple<Tree<T>>(left, middle, right);
}
#Override
public EitherOr<T, Triple<Tree<T>>> get() {
return EitherOr.right(branches);
}
}
}
Alright. Here is my idea for flattening:
public class MyFlattenTree<T> implements FlattenTree<T> {
public List<T> flattenInOrder(Tree<T> tree) {
List<T> list = new ArrayList<T>();
EitherOr<T, Triple<Tree<T>>> EitherOr;
EitherOr = tree.get();
// it is a leaf
if (EitherOr.isLeft()) {
// This is where the problem lies
// I don't how to get the value using a function f
list.add((T) EitherOr.ifLeft(f));
return list;
}
else {
// basically recursively go through the tree somehow
}
return null;
}
}
As I said, I am stuck with trying to retreive the value in the EitherOr class using the Function interface. I am thinking of implementing the Function interface and write a function for "apply" that just gets the value, but I am not sure how to do that. Any help would be appreciated. Thanks!
So, here is your flattenInOrder method:
public List<T> flattenInOrder(final Tree<T> tree) {
final EitherOr<T, Triple<Tree<T>>> EitherOr = tree.get();
if (EitherOr.isLeft()) {
return Collections.singletonList(EitherOr.ifLeft(this.ifLeftFunction));
}
return EitherOr.ifRight(this.ifRightFunction);
}
Quite simple, assuming that:
ifLeftFunction yields a single element (since EitherOr<T, Triple<Tree<T>>> has a single T elem' if it s "left")
... and:
ifRightFunction yields a collection of elements (since EitherOr<T, Triple<Tree<T>>> has a list of T elems' if it is "right")
Let's look into these functions now:
ifLeftFunction is... basic. I want to extract a T from... a T.
final Function<T, T> ifLeftFunction = new Function<T, T>() {
#Override
public T apply(final T t) {
return t;
}
};
ifRightFunction is slightly more complex: it has to be recursive and collect all Ts from the Tree it's browsing:
final Function<Triple<Tree<T>>, List<T>> ifRightFunction = new Function<Triple<Tree<T>>, List<T>>() {
#Override
public List<T> apply(final Triple<Tree<T>> t) {
final List<T> res = new ArrayList<>();
res.addAll(MyFlattenTree.this.flattenInOrder(t.left()));
res.addAll(MyFlattenTree.this.flattenInOrder(t.middle()));
res.addAll(MyFlattenTree.this.flattenInOrder(t.right()));
return res;
}
};
And... you're done!
Sample working code:
public class MyFlattenTree<T> {
private final Function<Triple<Tree<T>>, List<T>> ifRightFunction = new Function<Triple<Tree<T>>, List<T>>() {
#Override
public List<T> apply(final Triple<Tree<T>> t) {
final List<T> res = new ArrayList<>();
res.addAll(MyFlattenTree.this.flattenInOrder(t.left()));
res.addAll(MyFlattenTree.this.flattenInOrder(t.middle()));
res.addAll(MyFlattenTree.this.flattenInOrder(t.right()));
return res;
}
};
private final Function<T, T> ifLeftFunction = new Function<T, T>() {
#Override
public T apply(final T t) {
return t;
}
};
public static void main(final String[] args) {
final Tree<String> tree = new Node<>(new Leaf<>("1"), new Node<>(new Leaf<>("5"), new Leaf<>("4"), new Leaf<>("9")), new Leaf<>("6"));
System.out.println(new MyFlattenTree<String>().flattenInOrder(tree));
}
public List<T> flattenInOrder(final Tree<T> tree) {
final EitherOr<T, Triple<Tree<T>>> EitherOr = tree.get();
if (EitherOr.isLeft()) {
return Collections.singletonList(EitherOr.ifLeft(this.ifLeftFunction));
}
return EitherOr.ifRight(this.ifRightFunction);
}
}
Note that I'm creating the exact Tree you're featuring as an example in your question in the main method here:
public static void main(final String[] args) {
final Tree<String> tree = new Node<>(new Leaf<>("1"), new Node<>(new Leaf<>("5"), new Leaf<>("4"), new Leaf<>("9")), new Leaf<>("6"));
System.out.println(new MyFlattenTree<String>().flattenInOrder(tree));
}
Output: [1, 5, 4, 9, 6]
Cheers ;)
This is related to the following question:
How to improve the builder pattern?
I'm curious whether it's possible to implement a builder with the following properties:
Some or all parameters are required
No method receives many parameters (i.e., no list of defaults supplied to the initial builder factory method)
All builder fields can be reassigned an arbitrary number of times
The compiler should check that all parameters have been set
It is ok to require that parameters are initially set in some order, but once any parameter is set, all following builders can have this parameter set again (i.e., you can reassign the value of any field of the builder you wish)
No duplicate code should exist for setters (e.g., no overriding setter methods in builder subtypes)
One failed attempt is below (empty private constructors omitted). Consider the following toy builder implementation, and note that line with "Foo f2" has a compiler error because the inherited setter for a returns a BuilderB, not a BuilderFinal. Is there a way to use the java type system to parameterize the return types of the setters to achieve the above goals, or achieve them some other way.
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA newBuilder() {
return new BuilderC();
}
public static class BuilderA {
private volatile int a;
public BuilderB a(int v) {
a = v;
return (BuilderB) this;
}
public int a() {
return a;
}
}
public static class BuilderB extends BuilderA {
private volatile int b;
public BuilderC b(int v) {
b = v;
return (BuilderC) this;
}
public int b() {
return b;
}
}
public static class BuilderC extends BuilderB {
private volatile int c;
public BuilderFinal c(int v) {
c = v;
return (BuilderFinal) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).build();
Foo f2 = newBuilder().a(1).b(2).c(3).a(4).build();
}
}
Your requirements are really hard, but see if this generic solution fits the bill:
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA<? extends BuilderB<?>> newBuilder() {
return new BuilderFinal();
}
public static class BuilderA<T extends BuilderB<?>> {
private volatile int a;
#SuppressWarnings("unchecked")
public T a(int v) {
a = v;
return (T) this;
}
public int a() {
return a;
}
}
public static class BuilderB<T extends BuilderC<?>> extends BuilderA<T> {
private volatile int b;
#SuppressWarnings("unchecked")
public T b(int v) {
b = v;
return (T) this;
}
public int b() {
return b;
}
}
public static class BuilderC<T extends BuilderFinal> extends BuilderB<T> {
private volatile int c;
#SuppressWarnings("unchecked")
public T c(int v) {
c = v;
return (T) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC<BuilderFinal> {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).build();
Foo f2 = newBuilder().a(1).b(2).c(3).a(4).build();
}
}
To my knowledge the builder pattern should be used in case multiple parameters are used that make the invocation rather complicated as parameters might swap positions or not make it obviously clear what which parameter is for.
A rule of thumb would be to require compulsory parameters within the constructor of the builder and optional parameters within the methods. However, often more than 4 parameters may be required which makes the invocation again rather unclear and the pattern redundant. So a split up into default constructor and parameter setting for each parameter can also be used.
The checks should happen in a own method which is invoked within the build-method so you could invoke it using super. Compile-time security is only guaranteed on the correct data types (only exception - null is possible to, this has to be fetched within the checkParameters()-method). You can however force that all required parameters are set on requiring them within the Builder constructor - but as mentioned before, this may lead to a redundant pattern.
import java.util.ArrayList;
import java.util.List;
public class C
{
public static class Builder<T extends C, B extends C.Builder<? extends C,? extends B>> extends AbstractBuilder<C>
{
protected String comp1;
protected String comp2;
protected int comp3;
protected int comp4;
protected int comp5;
protected List<Object> comp6 = new ArrayList<>();
protected String optional1;
protected List<Object> optional2 = new ArrayList<>();
public Builder()
{
}
public B withComp1(String comp1)
{
this.comp1 = comp1;
return (B)this;
}
public B withComp2(String comp2)
{
this.comp2 = comp2;
return (B)this;
}
public B withComp3(int comp3)
{
this.comp3 = comp3;
return (B)this;
}
public B withComp4(int comp4)
{
this.comp4 = comp4;
return (B)this;
}
public B withComp5(int comp5)
{
this.comp5 = comp5;
return (B)this;
}
public B withComp6(Object comp6)
{
this.comp6.add(comp6);
return (B)this;
}
public B withOptional1(String optional1)
{
this.optional1 = optional1;
return (B)this;
}
public B withOptional2(Object optional2)
{
this.optional2.add(optional2);
return (B)this;
}
#Override
protected void checkParameters() throws BuildException
{
if (this.comp1 == null)
throw new BuildException("Comp1 violates the rules");
if (this.comp2 == null)
throw new BuildException("Comp2 violates the rules");
if (this.comp3 == 0)
throw new BuildException("Comp3 violates the rules");
if (this.comp4 == 0)
throw new BuildException("Comp4 violates the rules");
if (this.comp5 == 0)
throw new BuildException("Comp5 violates the rules");
if (this.comp6 == null)
throw new BuildException("Comp6 violates the rules");
}
#Override
public T build() throws BuildException
{
this.checkParameters();
C c = new C(this.comp1, this.comp2,this.comp3, this.comp4, this.comp5, this.comp6);
c.setOptional1(this.optional1);
c.setOptional2(this.optional2);
return (T)c;
}
}
private final String comp1;
private final String comp2;
private final int comp3;
private final int comp4;
private final int comp5;
private final List<?> comp6;
private String optional1;
private List<?> optional2;
protected C(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6)
{
this.comp1 = comp1;
this.comp2 = comp2;
this.comp3 = comp3;
this.comp4 = comp4;
this.comp5 = comp5;
this.comp6 = comp6;
}
public void setOptional1(String optional1)
{
this.optional1 = optional1;
}
public void setOptional2(List<?> optional2)
{
this.optional2 = optional2;
}
// further methods omitted
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.comp1);
sb.append(", ");
sb.append(this.comp2);
sb.append(", ");
sb.append(this.comp3);
sb.append(", ");
sb.append(this.comp4);
sb.append(", ");
sb.append(this.comp5);
sb.append(", ");
sb.append(this.comp6);
return sb.toString();
}
}
On extending D from C and also the builder, you need to override the checkParameters() and build() method. Due to the use of Generics the correct type will be return on invoking build()
import java.util.List;
public class D extends C
{
public static class Builder<T extends D, B extends D.Builder<? extends D, ? extends B>> extends C.Builder<D, Builder<D, B>>
{
protected String comp7;
public Builder()
{
}
public B withComp7(String comp7)
{
this.comp7 = comp7;
return (B)this;
}
#Override
public void checkParameters() throws BuildException
{
super.checkParameters();
if (comp7 == null)
throw new BuildException("Comp7 violates the rules");
}
#Override
public T build() throws BuildException
{
this.checkParameters();
D d = new D(this.comp1, this.comp2, this.comp3, this.comp4, this.comp5, this.comp6, this.comp7);
if (this.optional1 != null)
d.setOptional1(optional1);
if (this.optional2 != null)
d.setOptional2(optional2);
return (T)d;
}
}
protected String comp7;
protected D(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6, String comp7)
{
super(comp1, comp2, comp3, comp4, comp5, comp6);
this.comp7 = comp7;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(", ");
sb.append(this.comp7);
return sb.toString();
}
}
The abstract builder class is quite simple:
public abstract class AbstractBuilder<T>
{
protected abstract void checkParameters() throws BuildException;
public abstract <T> T build() throws BuildException;
}
The exception is simple too:
public class BuildException extends Exception
{
public BuildException(String msg)
{
super(msg);
}
}
And last but not least the main method:
public static void main(String ... args)
{
try
{
C c = new C.Builder<>().withComp1("a1").withComp2("a2").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println("c: " + c);
D d = new D.Builder<>().withComp1("d1").withComp2("d2").withComp3(3)
.withComp4(4).withComp5(5).withComp6("lala").withComp7("d7").build();
System.out.println("d: " + d);
C c2 = new C.Builder<>().withComp1("a1").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println(c2);
}
catch (Exception e)
{
e.printStackTrace();
}
}
Output:
c: a1, a2, 1, 4, 5, [lala]
d: d1, d2, 3, 4, 5, [lala], d7
Builders.BuildException: Comp2 violates the rules
... // StackTrace omitted
Though, before messing to much with Generics I'd suggest to stick to the KISS policy and forget inheritance for builders and code them simple and stupid (with part of them including dumb copy&paste)
#edit: OK, after all the work done and re-reading the OP as well as the linked post I had a totally wrong assumption of the requirements - like a German wording says: "Operation successful, patient is dead" - though I leave this post here in case someone wants a copy&paste like solution for a builder-inheritance which actually returns the correct type instead of the the base type
I had a crazy idea once, and it kind of goes against some of your requirements, but I think you can have the builder constructor take the required parameters, but in a way that makes it still clear which parameters are being set. Take a look:
package myapp;
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static class Builder {
private int a;
private int b;
private int c;
public Builder(A a, B b, C c) {
this.a = a.v;
this.b = b.v;
this.c = c.v;
}
public Builder a(int v) { a = v; return this; }
public Builder b(int v) { b = v; return this; }
public Builder c(int v) { c = v; return this; }
public Foo build() {
return new Foo(a, b, c);
}
}
private static class V {
int v;
V(int v) { this.v = v; }
}
public static class A extends V { A(int v) { super(v); } }
public static class B extends V { B(int v) { super(v); } }
public static class C extends V { C(int v) { super(v); } }
public static A a(int v) { return new A(v); }
public static B b(int v) { return new B(v); }
public static C c(int v) { return new C(v); }
public static void main(String[] args) {
Foo f1 = new Builder(a(1), b(2), c(3)).build();
Foo f2 = new Builder(a(1), b(2), c(3)).a(4).build();
}
}
For other clients, static imports are your friends:
package myotherapp;
import myapp.Foo;
import static myapp.Foo.*;
public class Program {
public static void main(String[] args) {
Foo f1 = new Builder(a(1), b(2), c(3)).build();
Foo f2 = new Builder(a(1), b(2), c(3)).a(4).build();
}
}
Building on Jordão's idea, I came up with the following, which may arguably satisfy all requirements 1-6 even though there is some duplicate code in the type parameters. Essentially, the idea is to "pass around" the return types of each method by using type parameters to override the return value of the inherited methods. Even though the code is verbose and impractical, and actually requires Omega(n^3) characters if you extend it out to an arbitrary number of fields n, I'm posting it because I think it's an interesting use of the java type system. If anyone can find a way to reduce the number of type parameters (especially asymptotically), please post in the comments or write another answer.
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA<? extends BuilderB<?, ?>, ? extends BuilderC<?, ?>> newBuilder() {
return new BuilderFinal();
}
public static class BuilderA<B extends BuilderB<?, ?>, C extends BuilderC<?, ?>> {
private volatile int a;
#SuppressWarnings("unchecked")
public B a(int v) {
a = v;
return (B) this;
}
public int a() {
return a;
}
}
public static class BuilderB<B extends BuilderB<?, ?>, C extends BuilderC<?, ?>> extends BuilderA<B, C> {
private volatile int b;
#SuppressWarnings("unchecked")
public C b(int v) {
b = v;
return (C) this;
}
public int b() {
return b;
}
}
public static class BuilderC<B extends BuilderC<?, ?>, C extends BuilderC<?, ?>> extends BuilderB<B, C> {
private volatile int c;
#SuppressWarnings("unchecked")
public BuilderFinal c(int v) {
c = v;
return (BuilderFinal) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC<BuilderFinal, BuilderFinal> {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).a(2).build();
Foo f2 = newBuilder().a(1).a(2).c(3).build(); // compile error
Foo f3 = newBuilder().a(1).b(2).a(3).b(4).b(5).build(); // compile error
}
}
Why don't you want to override the setters in BuilderFinal? They would just need to downcast the super method:
public static class BuilderFinal extends BuilderC {
#Override
public BuilderFinal a(int v) {
return (BuilderFinal) super.a(v);
}
#Override
public BuilderFinal b(int v) {
return (BuilderFinal) super.b(v);
}
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
I'm trying to figure out why i keep getting the error that my AM class does not override abstract method. In my teachers UML diagram it only shows that i need the equals (Object o) method in my parent radio class. Also i'm not declaring it as abstract in my abstract class.
public abstract class Radio implements Comparable
{
double currentStation;
RadioSelectionBar radioSelectionBar;
public Radio()
{
this.currentStation = getMin_Station();
}
public abstract double getMax_Station();
public abstract double getMin_Station();
public abstract double getIncrement();
public void up()
{
}
public void down()
{
}
public double getCurrentStaion()
{
return this.currentStation;
}
public void setCurrentStation(double freq)
{
this.currentStation = freq;
}
public void setStation(int buttonNumber, double station)
{
}
public double getStation(int buttonNumber)
{
return 0.0;
}
public String toString()
{
String message = ("" + currentStation);
return message;
}
public boolean equals (Object o)
{
if (o == null)
return false;
if (! (o instanceof Radio))
return false;
Radio other = (Radio) o;
return this.currentStation == other.currentStation;
}
public static void main(String[] args)
{
Radio amRadio = new AMRadio();
System.out.println(amRadio);
Radio fmRadio = new FMRadio();
System.out.println(fmRadio);
Radio xmRadio = new XMRadio();
System.out.println(xmRadio);
}
}
public class AMRadio extends Radio
{
private static final double Max_Station = 1605;
private static final double Min_Station = 535;
private static final double Increment = 10;
public AMRadio()
{
currentStation = Min_Station;
}
public double getMax_Station()
{
return this.Max_Station;
}
public double getMin_Station()
{
return this.Min_Station;
}
public double getIncrement()
{
return this.Increment;
}
public String toString()
{
String message = ("AM " + this.currentStation);
return message;
}
}
You have to implement the compareTo() method, given that Radio implements the Comparable interface and a concrete implementation for this method wasn't provided in the Radio class, so you have two choices:
Implement compareTo() in all of Radio's subclasses
Or implement compareTo() in Radio
Something like this, in AMRadio:
public int compareTo(AMRadio o) {
// return the appropriate value, read the linked documentation
}
Or like this, in Radio:
public int compareTo(Radio o) {
// return the appropriate value, read the linked documentation
}