How to bypass Java not being able to extend from multiple classes - java

I think I have a design problem in my Java app, but I cannot figure out how to solve or bypass it.
Say I have an interface and an abstract class implementing it as follows:
public interface IntegerCollection extends Collection<Integer> {
public int sum();
}
public abstract class AbstractIntegerCollection
extends AbstractCollection<Integer> implements IntegerCollection {
public int sum() {
// fancy code to calculate the sum of all collection members (just an example)
}
}
Now I would want to make this class instantiable by using the existing implementations of Collection (e.g., LinkedList); something like this:
public class IntegerLinkedList extends AbstractIntegerCollection, LinkedList<Integer> {
}
IntegerCollection ic = new IntegerLinkedList();
However, this does not work because Java does not support extending several classes. Also it looks quite ugly to me, as there is a mixture of hierarchies.
Of course, I could let IntegerLinkedList implement IntegerCollection instead of letting it extend AbstractIntegerCollection. But then, I would have to repeat the code for sum() in all other implementations (e.g., IntegerArrayList).
Is there a better way to do this?

I'm not sure what exactly, you are trying to achieve, but rather you could implements List instead of extending LinkedList
public class IntegerLinkedList
extends AbstractIntegerCollection
implements List<Integer>
{
}
But, you need to implements all abstract method of List.

Since java 8 it has been possible to include implementations in an interface by using the default keyword. Therefore you don't need AbstractIntegerCollection - all the common code can be put in the interface. Here is an example:
import java.util.Collection;
import java.util.LinkedList;
public class Main {
interface IntegerCollection extends Collection<Integer> {
default int sum() {
int sum = 0;
for (int a : this)
sum += a;
return sum;
}
}
static class IntegerLinkedList extends LinkedList<Integer> implements IntegerCollection {
}
public static void main(String[] args) {
IntegerCollection list = new IntegerLinkedList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.sum()); // Prints 6
}
}
This works, but I'm not sure it's a good idea. I'd think very carefully before extending a class like LinkedList. Some people also consider it an anti-pattern to extend generic classes with non-generic ones.
Another thing to be aware of is that it is not possible to write default methods for the methods of Object like equals and toString etc.
Since you are using Java 7, the above solution is not available. However, with a load of tedious forwarding methods, you can do it using composition rather than inheritance. Josh Bloch's book Effective Java gives a very good explanation of why composition is preferable anyway. Here is an (incomplete) example - you'll need to add a few more forwarding methods to avoid UnsupportedOperationExceptions when you try doing other things with the list.
import java.util.*;
public class Main {
abstract static class AbstractIntegerCollection extends AbstractCollection<Integer> {
public int sum() {
int sum = 0;
for (int a : this)
sum += a;
return sum;
}
}
static class IntegerLinkedList extends AbstractIntegerCollection implements List<Integer> {
private final List<Integer> list = new LinkedList<>();
#Override
public Iterator<Integer> iterator() {
return list.iterator();
}
#Override
public int size() {
return list.size();
}
#Override
public boolean addAll(int index, Collection<? extends Integer> c) {
return list.addAll(index, c);
}
#Override
public Integer get(int index) {
return list.get(index);
}
#Override
public Integer set(int index, Integer element) {
return list.set(index, element);
}
#Override
public boolean add(Integer element) {
return list.add(element);
}
#Override
public void add(int index, Integer element) {
list.add(index, element);
}
#Override
public Integer remove(int index) {
return list.remove(index);
}
#Override
public int indexOf(Object o) {
return list.indexOf(o);
}
#Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
#Override
public ListIterator<Integer> listIterator() {
return list.listIterator();
}
#Override
public ListIterator<Integer> listIterator(int index) {
return list.listIterator(index);
}
#Override
public List<Integer> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
// More of these
}
public static void main(String[] args) {
IntegerLinkedList list = new IntegerLinkedList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.sum()); // Prints 6
}
}
This solution is far from perfect. For one thing, it would be better if IntegerLinkedList extended AbstractList<Integer> rather than just AbstractCollection<Integer>, but then you couldn't extend AbstractIntegerCollection too.

Related

Implementing a functional interface via method reference

First I got a class named after my Chinese name
public class Yxj<T> {
private T[] data;
private int size = 0;
private final Comparator<? super T> comparator;
public Yxj(Comparator<? super T> c) {
data= (T[]) new Object[16];
comparator = c;
}
public void addItem(T t){
data[size++] = t;
}
public int sort(){
return comparator.compare(data[0], data[1]);
}
public T[] getData(){
return data;
}
}
in which a Comparator resides,then I defined a Norwich keeping a field order and setter and getter of it, finally there's a method used to implement the compare(T t1,T t2) in Comparator.
public class Norwich {
private int order;
public Norwich(int o) {
order = o;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int compareOrder(Norwich n) {
if (order > n.getOrder()) {
return 2;
} else if (order == n.getOrder()) {
return 0;
} else {
return -3;
}
}
}
then here comes the main method
Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
norwichYxj.addItem(new Norwich(9));
norwichYxj.addItem(new Norwich(1));
System.out.println(norwichYxj.sort());
so what I'm interested in is that, why does not the method compareOrder keep the same parameters as the compare in Comparator but it can still work correctly?
It is simple. You have passed through the constructor your implementation of the Comparator to be used for comparing.
Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
Remember Comparator is nothing else than an interface. Since it is a functional interface, it can be represented through a lambda expression or a
method reference (as you did). The way you can pass the Comparator in the full form is as follows. Note the usage of the compareOrder method:
Yxj<Norwich> norwichYxj = new Yxj<>(new Comparator<>() {
#Override
public int compare(Norwich o1, Norwich o2) {
return o1.compareOrder(o2); // usage of compareOrder
}
});
This can be shortened to a lambda expression:
Yxj<Norwich> norwichYxj = new Yxj<>((o1, o2) -> o1.compareOrder(o2));
It can be shortened again to a method reference:
Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
Now you can see it can be represented in this way though the method compareOrder accepts only one formal parameter. The first parameter of the Comparator#compare method is the one invoking the compareOrder method and the second parameter is the one being passed to the compareOrder method.
Learn more here: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
Additionally, the classes you have constructed look a bit odd. Though the other answer doesn't in fact answer your question, it can lead you to a better code: Implementing a functional interface via method reference
class Yxj
The paramter T of your class Yxj should have more restrictions if you want to compare/sort in this class with T then say T must be comparable.
If your T array grows then don't implement your own growing array but use ArrayList instead which does that for you
If you do the first you don't need the Comperator anymore
Your methode sort only sorts the first and second element so you will get problems. If the data is shorter you will get an ArrayIndexOutOfBoundsException if it is longer it won't sort the rest of elements. So with a Collection you could simple use Collections.sort(data);
public class Yxj<T extends Comparable<T>> {
private final List<T> data;
public Yxj() {
this.data = new ArrayList<>();
}
public void addItem(T t){
data.add(t);
}
public void sort(){
Collections.sort(data);
}
public List<T> getData(){
return data;
}
public void print(){
System.out.println(data);
}
}
class Norwich
If you done the above know your Norwich class must implement the Comparable interface so you can compare Norwich instances with the methode compareTo which also will be called each time you or the API ask directly or indirectly to compare to Norwich instances like for sorting ect.
public class Norwich implements Comparable<Norwich> {
private int order;
public Norwich(int o) {
this.order = o;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
#Override
public int compareTo(Norwich other) {
return this.order - other.order;
}
#Override
public String toString() {
return "Norwich{" +
"order=" + order +
'}';
}
}
Main
Done? Perfect, then your main could be looks like this
public static void main(String[] args) {
Yxj<Norwich> norwichYxj = new Yxj<>();
norwichYxj.addItem(new Norwich(9));
norwichYxj.addItem(new Norwich(1));
norwichYxj.sort();
norwichYxj.print();
}

Strange bug with Streams

So I have created my own Set, which is just a regular set, but has additional functions (for example my set only stores absolute values).
Here is my Code:
import java.util.*;
public class SortedByAbsoluteValueIntegerSet<E> extends HashSet<E> {
private Set<Integer> mySet;
public SortedByAbsoluteValueIntegerSet() {
mySet = new HashSet<Integer>();
}
#Override
public int size() {
return mySet.size();
}
#Override
public boolean add(E e){
return mySet.add(Math.abs((Integer) e));
}
#Override
public boolean remove(Object o) {
return mySet.remove(o);
}
#Override
public boolean contains(Object o){
return mySet.contains(o);
}
#Override
public boolean addAll(Collection<? extends E> c) {
List<Integer> myList = new ArrayList<>();
for (Object e: c) {
myList.add(Math.abs((Integer) e));
}
return mySet.addAll(myList);
}
#Override
public String toString(){
return mySet.toString();
}
}
I had a test case in JUnit, which failed. Because there was some issue with my code. For demonstration purpose, and for me to explain my issue better I have created two functions, which show the problem well.
Here is the problem:
public static void testSortedByAbsoluteValueIntegerSet() {
Set<Integer> set1 = new SortedByAbsoluteValueIntegerSet();
Set<Integer> set2 = new HashSet<>();
set1.add(5);
set1.add(3);
set2.add(5);
set2.add(3);
String x = toString(set1); //x is ""
String t = toString(set2); //t is "3 5"
}
public static String toString(final Collection<Integer> collection) {
return String.join(" ", collection.stream()
.map(i -> Integer.toString(i))
.toArray(String[]::new));
}
So the problem arises in this line:
String x = toString(set1); //x is always an empty string
String t = toString(set2); //t works correctly
When I go through debugger I see that String x is always an empty String and String t works correctly. By the way set1 is representation of my created set and set2 is just a regular hashset.
The question is: how can I fix my SortedByAbsoluteValueIntegerSet class so that the toString() method worked fine with my own created set as well.
P.S I am new to streams and I don't really understand the problem, why does it happens.
It's because you're extending HashSet but also using an internal Set.
When adding, you're adding to the internal Set but when using collection.stream() it calls the inherited HashSet (which is empty).
Easiest for you I beleive would be to remove the internal 'mySet' and call the inherited methods in your overridden methods.
For instance, your add method would be
#Override
public boolean add(E e){
return super.add(Math.abs((Integer) e));
}
(and then you don't need to override size, remove, contains of toString or spliterator)
Full example:
import java.util.*;
public class SortedByAbsoluteValueIntegerSet extends HashSet<Integer> {
#Override
public boolean add(Integer e){
return super.add(Math.abs(e));
}
#Override
public boolean addAll(Collection<? extends Integer> c) {
List<Integer> myList = new ArrayList<>();
for (Integer e: c) {
myList.add(Math.abs(e));
}
return super.addAll(myList);
}
}
I think Tomas F gave better answer
Main problem in your set is using HashSet mySet as field and extending HashSet. In java better to use (field) composition instead of extending to add some functionality to your class. Here you tried use both - it's not a good idea.
Best decision is to use just composition and extending more general class, for example AbstractSet<Integer> and Set<Integer>:
import java.util.*;
public class SortedByAbsoluteValueIntegerSet extends AbstractSet<Integer>
implements Set<Integer>, java.io.Serializable {
private final Set<Integer> mySet;
public SortedByAbsoluteValueIntegerSet() {
mySet = new HashSet<>();
}
#Override
public Iterator<Integer> iterator() {
return mySet.iterator();
}
#Override
public int size() {
return mySet.size();
}
#Override
public boolean add(Integer e) {
return mySet.add(Math.abs(e));
}
#Override
public boolean remove(Object o) {
return mySet.remove(o);
}
#Override
public boolean contains(Object o) {
return mySet.contains(o);
}
#Override
public boolean addAll(Collection<? extends Integer> c) {
List<Integer> myList = new ArrayList<>();
for (Integer e : c) {
myList.add(Math.abs(e));
}
return mySet.addAll(myList);
}
#Override
public String toString() {
return mySet.toString();
}
}
in this case you don't have to implement spliterator, because Set has default implementation using this keyword (which is refer to your set as a Collection)
but also you can implement spliterator in your class (but using such extends and internal Set fields are the bad practice. Also, it's better to get rid of type parameter E and casting elements to Integer:
import java.util.*;
public class SortedByAbsoluteValueIntegerSet extends HashSet<Integer> {
private Set<Integer> mySet;
public SortedByAbsoluteValueIntegerSet() {
mySet = new HashSet<>();
}
#Override
public int size() {
return mySet.size();
}
#Override
public boolean add(Integer e){
return mySet.add(Math.abs(e));
}
#Override
public boolean remove(Object o) {
return mySet.remove(o);
}
#Override
public boolean contains(Object o){
return mySet.contains(o);
}
#Override
public boolean addAll(Collection<? extends Integer> c) {
List<Integer> myList = new ArrayList<>();
for (Integer e: c) {
myList.add(Math.abs(e));
}
return mySet.addAll(myList);
}
#Override
public String toString(){
return mySet.toString();
}
#Override
public Spliterator<Integer> spliterator() {
return mySet.spliterator();
}
}

java generics - how to implement a class that takes a HashSet<T>?

Normally when you implement a generic, you have some type T that you want to generalize. I want to write a class that generalizes a HashSet<T>.
I'm trying to write this the following way, but it's not the correct syntax or maybe it's not supported:
public class PermutationHelper<T> implements Iterable<T> {
private HashSet<T> m_set;
private long numberOfPermutations;
private boolean includeEmptyPermutationAsOutput = false;
public PermutationHelper(HashSet<T> set) {
m_set = set;
numberOfPermutations = 2 ^ set.size();
}
public void setIncludeEmptyPermutationAsOutput(boolean value) {
includeEmptyPermutationAsOutput = value;
}
#Override
public Iterator<T> iterator() {
Iterator<T> it = new Iterator<T>() {
long currentIndex = (includeEmptyPermutationAsOutput ? 0 : 1);
#Override
public boolean hasNext() {
return currentIndex < numberOfPermutations;
}
#Override
public T next() {
HashSet<T> result = new HashSet<T>();
return result; // expects T, but is a HashSet<T>..
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
I want the Iterator to give me all subsets of the passed-in HashSet<T>.
You can easly do
public class PermutationHelper<T extends HashSet<T>> implements Iterable<T>
in order to 'force' the generic type to be an HashSet or a subtype of a HashSet
What you want is simply
public class PermutationHelper<T> implements Iterable<HashSet<T>>
Your class is generic. You choose to name its generic type T. And it implements Iterable<HashSet<T>>, which means it must have a method
public Iterator<HashSet<T>> iterator()

Java sort through 3 classes

how can I sort Event by index?
simple view of my project:
class Event{
int index;
}
class EventField{
Event[] field;
}
class Action{
EventField ev;
ev.sort(); // Sort event in field EventField by index
}
Use Arrays.sort() with Comparator<Event> which is using Integer.compare()
Arrays.sort(ev.field, new Comparator<Event>(){
#Override
public int compare(Event e1, Event e2) {
return Integer.compare(e1.index, e2.index)
}
});
You need to implement method in EventField
class EventField{
Event[] field;
public void sort(){ Arrays.sort(field, yourCustomComparatorInstance }
}
that does sorting using a custom Comparator on Event
Related:
Sorting a list of points with Java
See
Arrays.sort()
In java you have 2 ways to define order you can create a Comparator for creating your sort strategy, or define natural-order of your class implementing Comparable
Example using Comparator:
class Event{
private int index;
public static final Comparator<Event> INDEX_COMPARATOR = new MyComparator();
//TODO define getters and setter equals & hashCode cause it's strong recommended
static class MyComparator implements Comparator<MyClass>{
#Override
public int compare(Event o1, Event o2) {
return Integer.valueOf(o1.index).compareTo(o2.index);
}
}
}
And then in EventField.
Example:
class EventField{
Event[] fields;
public void sort(){
Arrays.sort(fields,Event.INDEX_COMPARATOR );
}
}
Read more : Collections#sort(..)
If you want to define natural-ordering of your class just define
public class Event implements Comparable<Event>{
private int index;
//define getter&setter & recommended equals & hashCode
#Override
public int compareTo(Event o) {
return Integer.valueOf(index).compareTo(o.index);
}
}
And in EventField code:
Arrays.sort(fields); // where fields is Event[]
If events are naturally something you'll be comparing a lot in your program, you can extend the Comparable interface:
public class Event implements Comparable<Event> {
private int index;
public int getIndex() {
return index;
}
#Override
public int compareTo(Event o) {
return index == o.getIndex() ? 0 : (index > o.getIndex() ? 1 : -1);
}
}
Then you can call Arrays.sort(ev.getField()). If the objects in 'field' are always going to be sorted, then you can just keep its objects sorted whenever you add something to it.

Implement Java Iterator and Iterable in same class?

I am trying to understand Java Iterator and Iterable interfaces
I am writing this class
class MyClass implements Iterable<String> {
public String[] a = null;
public MyClass(String[] arr) {
a = arr;
}
public MyClassIterator iterator() {
return new MyClassIterator(this);
}
public class MyClassIterator implements Iterator<String> {
private MyClass myclass = null;
private int count = 0;
public MyClassIterator(MyClass m) {
myclass = m;
}
public boolean hasNext() {
return count < myclass.a.length;
}
public String next() {
int t = count;
count++;
return myclass.a[t];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
It seems to be working.
Should I have:
Myclass implements Iterable<Stirng>, Iterator<String> {
}
Or I should put MyClassIterator outside MyClass as
class MyClass implements Iterable<String> {
public String[] a = null;
public MyClass(String[] arr) {
a = arr;
}
public MyClassIterator iterator() {
return new MyClassIterator(this);
}
}
public class MyClassIterator implements Iterator<String> {
private MyClass myclass = null;
private int count = 0;
public MyClassIterator(MyClass m) {
myclass = m;
}
public boolean hasNext() {
return count < myclass.a.length;
}
public String next() {
int t = count;
count++;
return myclass.a[t];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Which one is better?
You should almost never implement both Iterable and Iterator in the same class. They do different things. An iterator is naturally stateful - as you iterate using it, it has to update its view of the world. An iterable, however, only needs to be able to create new iterators. In particular, you could have several iterators working over the same original iterable at the same time.
Your current approach is pretty much okay - there are aspects of the implementation I'd change, but it's fine in terms of the separation of responsibilities.
You were on track with your first try. MyClass only needs to implement Iterable<String>, which in turn requires you to provide an Iterator<String> implementation to return from Iterable<String>.iterator().
There's no need to put the MyClassIterator outside of MyClass because in most cases you will never even need to directly use the Iterator<String> (it's used implicitly by the for .. in .. syntax on Iterable<String>s), and in all other cases the interface is sufficient unless you actually add additional behavior to the implementation (which you likely won't ever need to do).
Here's how I'd do it, see comments inlined:
import java.util.Iterator;
class MyClass implements Iterable<String>{
public String[] a=null; //make this final if you can
public MyClass(String[] arr){
a=arr; //maybe you should copy this array, for fear of external modification
}
//the interface is sufficient here, the outside world doesn't need to know
//about your concrete implementation.
public Iterator<String> iterator(){
//no point implementing a whole class for something only used once
return new Iterator<String>() {
private int count=0;
//no need to have constructor which takes MyClass, (non-static) inner class has access to instance members
public boolean hasNext(){
//simplify
return count < a.length;
}
public String next(){
return a[count++]; //getting clever
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
}
You should not do Myclass implements Iterable<String>,Iterator<String>{ since iterators are single-use. With the exception of list iterators, there's no way to return them to the start.
Incidentally, you can skip the
MyClass myClass;
public MyClassInterator(MyClass m){
myclass=m;
}
and instead of referencing
myClass
reference
MyClass.this
Your inner class is not static, so MyClass.this will reference the instance of the enclosing class that created it.

Categories

Resources