Template method pattern in java - java

I have assignment in java ,I need help please.
I tried to solve it but I have some problem that can't understand them.
Assignment is:
In this exercise, use the Template method pattern to define an abstract class Filter with a public method filter (the template method) that calls the method accept (the hook method) that can be implemented in different ways in the different concrete classes. Write a test program by extending the class Filter and defining accept so that only strings of at most three characters are accepted.
public abstract class Filter<T> {
public abstract T[] filter(T[] list);
public abstract boolean accept(T val);
}
public class FilterTest<T> extends Filter<T> {
private int capacity = 0;
public FilterTest(int cap) {
this.capacity = cap;
}
#Override
public T[] filter(T[] list1) {
#SuppressWarnings("unchecked")
T[] finalList = (T[]) Array.newInstance(list1.getClass().getComponentType(), capacity);
int counter = 0;
for (T t : list1) {
if (accept(t)) {
finalList[counter] = t;
counter++;
}
}
return finalList;
}
public void printArray(T[] list2) {
for (int i = 0; i < list2.length; i++) {
if (list2[i] != null) {
System.out.print(list2[i] + " ");
}
}
System.out.println();
}
#Override
public boolean accept(T val) {
return String.valueOf(val).length() > 0 &&
String.valueOf(val).length() <= 3;
}
public static void main(String[] args) {
FilterTest<String> filterTest = new FilterTest<>(8);
String[] lists = {
"Hi", "here", "is", "the", "AOOP", "course", "at", "University"
};
System.out.print("My original list is: ");
filterTest.printArray(lists);
System.out.print(" The filtered list is: ");
String[] filteredList = filterTest.filter(lists);
filterTest.printArray(filteredList);
}
}
Here is comment from my teacher:
"not correct, only the accept method should be abstract in the Filter class, the filter method should be already implemented in the Filter class and not be abstract all implementation will be the same, only the accept method changes for different filters)".
I don't understand what should I do now, how the code will be correct.
help please,
Thanks

I assume that Filter should look something like this
public abstract class Filter<T> {
public T[] filter(T[] list1) {
#SuppressWarnings("unchecked")
T[] finalList = (T[]) Array.newInstance(list1.getClass().getComponentType(), capacity);
int counter = 0;
for (T t : list1) {
if (accept(t)) {
finalList[counter] = t;
counter++;
}
}
return finalList;
}
public abstract boolean accept(T val);
}
You can even declare Filter<T> as an interface and have a default implementation for filter. Have a look here

Related

Interface to unite calculate methods with different primitive paramter types

I have two types of objects that can perform a calculate() operation with either an int or a byte:
public class A {
public int calculate(int n) {...}
}
and
public class B {
public byte calculate(byte n) {...}
}
I want to have an ArrayList of objects that I can loop over calling the calculate method.
How do I do that, using an interface?
Considering the difference in the int/byte signature
Would something like this be a good approach?
public interface Calculatable {
int calculate(int number);
default byte calculate(byte number) {
return (byte) calculate((int) number);
}
}
Maybe using a 3-rd class and check based on type could be useful
public class TestCalc {
public static void main(String[] args) {
List<Object> l = new ArrayList<Object>();
l.add(Integer.valueOf(300));
l.add(Byte.valueOf("120"));
l.add(Integer.valueOf(1));
TestCalc tc = new TestCalc();
ComputeAB cab = tc.new ComputeAB();
for (Object o : l) {
System.out.println(cab.calculate(o) + ":" + cab.type);
}
}
class A {
public int calculate(int n) {
return n;
}
}
class B {
public byte calculate(byte n) {
return n;
}
}
class ComputeAB {
String type = "";
public Object calculate(Object o) {
if (o instanceof Integer) {
type = "int";
return new A().calculate((int) o);
}
type = "byte";
return new B().calculate((byte) o);
}
}
}
Output
300:int
120:byte
1:int

binarySearch with generics and capture of

I have a Task:
public interface Task {
}
Then I have implementations for those:
public interface Task__Init extends Task {
void init(Element e);
}
public interface Task__Hit_Test extends Task {
boolean hit_test(Element e, float x, float y);
}
public interface Task__Draw extends Task {
void draw(Element e);
}
I also have a class that can hold a instance of those implementations:
static public class Task_Holder<T extends Task> {
public int task_id;
public Task_Type type;
public T task;
// ...
}
Then I have a class that holds those, where the last ArrayList holds all of them (all_task_holders)
static public class Implementation_Context {
public HashMap<String, ArrayList<Task_Holder<Task__Init>>> init_solvers = new HashMap<>();
public HashMap<String, ArrayList<Task_Holder<Task__Draw>>> draw_solvers = new HashMap<>();
public HashMap<String, ArrayList<Task_Holder<Task__Hit_Test>>> hit_test_solvers = new HashMap<>();
public ArrayList<Task_Holder<? extends Task>> all_task_holders = new ArrayList<>();
// ...
}
Now one of the problem arises:
static public Task_Holder<?> find_task_holder(int task_id) {
Comparator<Task_Holder<?>> comparator = (a, b)-> {
if (a.task_id < b.task_id) return -1;
if (a.task_id > b.task_id) return 1;
return 0;
};
Collections.sort(ctx.implementation.all_task_holders, comparator);
Task_Holder<?> key = new Task_Holder<>();
key.task_id = task_id;
int index = Collections.binarySearch(ctx.implementation.all_task_holders, key);
for (Task_Holder<?> th : ctx.implementation.all_task_holders) {
if (th.task_id == task_id) {
return th;
}
}
assert false; // should we find things that are not there?
return null;
}
For the binarySearch I get (I make it a codeblock here, else stackoverflow removes words for some reason?):
The method binarySearch(List<? extends Comparable<? super T>>,
T) in the type Collections is not applicable for the arguments
(ArrayList<sfjl_ui.Task_Holder<?>>, sfjl_ui.Task_Holder<capture#6-of
?>)
I have no clue how to fix this. Every attempt breaks other things (for example I break the sort that's 3 lines higher).
It feels like paying off credit card debts with other credit cards, you never win.
How can I fix this?
Pass the comparator as an additional argument:
int index = Collections.binarySearch(ctx.all_task_holders, key, comparator);

Generalized List as a parameter for a method

Say I have a simple class like this:
public class BasicObject {
private String name;
public BasicObject (String str) {
name = str;
}
public String getName () {
return name;
}
}
then I have some simple method in the main class like this:
private static int findInList (____ list, String str) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().equalsIgnoreCase(str)) {
return i;
}
}
return -1;
}
It would work if I put List<BasicObject> on the blank for the parameter list, but what if I have other objects? Can I generalize the list so this would work with other objects besides BasicObject? If so, how can I get the type of the objects in the list?
Edit: What if I have another class from an imported package that I can still put in a list but I don't want to change what it implements? Is there a way to have a generalized findInList that includes those too? Or do I have to just make another method for that? I'm fine with just making another method, but I'm curious if this way is possible.
You can use an interface structure such as this
Doing so provides a common call structure, so it is predictable what can be called from the implementations
public interface IShape {
String getName();
}
public class Square implements IShape {
private String name = "Square";
#Override
public String getName() {
return name;
}
}
public class Circle implements IShape {
private String name = "Circle";
#Override
public String getName() {
return name;
}
}
public static void main(String[] args){
List<IShape> list = new ArrayList<>();
list.add(new Square());
list.add(new Circle());
list.add(new Circle());
list.add(new Square());
list.add(new IShape() {
#Override
public String getName() {
return "Triangle";
}
});
for(IShape test : list){
System.out.println(test.getName());
}
}
this produces an output like this
Square
Circle
Circle
Square
Triangle
as answer to edit
Yes, but requires reflection, if help is needed on this, please open a new question after proberly trying to solve the issue yourself.
Have you tried checking generics? It is what you're looking for, your method signature should look like below:
public <T> List<T> findInList (Class<T> list, String str) {}
This will work if all objects have common parent (BasicObject or any other class which have getName() method).
private static int findInList (List<? extends BasicObject> list, String str) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().equalsIgnoreCase(str)) {
return i;
}
}
return -1;
}
Your code relies on the list having an element type with a getName method that is visible to the compiler. Another way is to use lambdas. For example,
public interface Named {
String getName();
}
public class UseNamed<T extends Named> {
public int findIndex(List<T> nameds, String search) {
for (int len = nameds.size(), ix = 0; ix < len; ++ix) {
final Named named = names.get(ix);
if (search.equalsIgnoreCase(named.getName())) {
return ix;
}
}
return -1;
}
One approach with lambdas is to pass a comparer to findIndex:
public <T, K> int findIndex(List<T> stuff, K search,
BiFunction<T, K, Boolean> compares) {...}
and call it with
List<Named> stuff = ...;
String search = ...;
int index = findIndex(stuff, search,
(named, s) -> s.equalsIgnoreCase(named.getName()));

Writing an iterator for my own array list class in Java

I am writing an iterator method for my own array list class, however, when I try to test the class it says foreach loop is not applicable to MyArrayList. can anyone help me out with where I have gone wrong?
The class itself uses arrays of objects and the necessary methods to act like an arraylist (add, remove, get etc.)
Here is the class constructor and my iterator class:
public class MyArrayList {
public Object[] arrayList = new Object[5];
int length1 = 5;
public MyArrayList() {
}
public MyArrayList(Object[] arrayList) {
this.arrayList = arrayList;
length1 = arrayList.length;
}
public ArrayListIterator iterator(){
return new ArrayListIterator(this);
}
class ArrayListIterator<MyArrayList> implements Iterator<Object> {
private Object[] arrayListIterable;
private int count = 0;
public ArrayListIterator(Object[] x){
arrayListIterable = x;
}
public ArrayListIterator(MyArrayList myArrayList) {
}
public boolean hasNext(){
if(count < arrayList.length){
return true;
}else{
return false;
}
}
public Object next(){
int x = count;
count++;
return arrayListIterable[x];
}
}
Your MyArrayList class must implement Iterable<T> interface.
Check the javadoc for Iterable:
Implementing this interface allows an object to be the target of the "for-each loop" statement.

How do I write a method which would work on both lists and arrays?

I have a method which looks like this:
void foo (List<String> list, ...) {
...
for (String s : list) { // this is the only place where `list` is used
...
}
...
}
the exact same code would work if I replace List<String> list with String[] list, however, to avoid spaghetti code, I keep the single method, and when I need to call it on an array a, I do it like this: foo(Arrays.asList(a)).
I wonder if this is The Right Way.
Specifically,
What is the overhead of Arrays.asList()?
Is there a way to write a method which would accept both arrays and lists, just like the for loop does?
Thanks!
Arrays.asList() has a small overhead. There is no real way to implement one method for both List and arrays.
But you can do the following:
void foo (List<String> list, ...) {
...
for (String s : list) { // this is the only place where *list* is used
...
}
...
}
void foo (String[] arr, ...) {
if ( arr != null ) {
foo(Arrays.asList(arr),...);
}
}
From the source code of openjdk, Arrays.asList:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
furthermore:
ArrayList(E[] array) {
if (array==null)
throw new NullPointerException();
a = array;
}
So basically all that happens in an assignment, so the overhead should be negligible.
The overhead is that it converts an array to a list--how it does so would be implementation-dependent, it only needs to fulfill the contract.
IMO you should write two methods if you're concerned about the potential runtime overhead: that is the nature of Java; methods have type signatures, and they must be obeyed.
Do avoid this I just use and allow Lists, Sets and Maps (like Joshua Bloch told us). There is no way to merge both "collection types".
An alternative is to use guava (Iterators/Iteratables). So you can iterarte over your collections without a deep copy of them.
Good question.
This is a very common case, and is often dealt with by writing two separate methods. However code duplication is really a bad idea, and whenever you find yourself duplicating code, you should start looking for opportunities to factor your code better. (As you are doing right now!)
Now if you look into the source of java.util.Arrays, you will notice that Arrays.asList retruns an instance of a private inner class Arrays.ArrayList which is just a thin wrapper over plain arrays, and delegates all relevant method calls to it. (This is known as a projection or view of a data structure.) Therefore the overhead incurred is insignificant (unless you are striving to extract every last bit of performance), and in my opinion, you should go ahead and use this method without worrying about performance.
The solution I personally use is as follows.
I have a class named RichIterable in my personal utils. As the name indicates the class wraps over Iterable and provides some additional useful methods not already present. The class also has a factory method that creates an RichIterable from an array. Here is the class definition.
public class RichIterable<A> implements Iterable<A> {
private Iterable<A> xs;
private RichIterable(Iterable<A> xs) {
this.xs = xs;
}
public static <A> RichIterable<A> from(Iterable<A> xs) {
if (xs instanceof RichIterable) {
return (RichIterable<A>) xs;
} else {
return new RichIterable<A>(xs);
}
}
public static <A> RichIterable<A> from(final Enumeration<A> xs) {
Iterable<A> iterable = new Iterable<A>() {
#Override
public Iterator<A> iterator() {
return new Iterator<A>() {
#Override
public boolean hasNext() {
return xs.hasMoreElements();
}
#Override
public A next() {
return xs.nextElement();
}
#Override
public void remove() {
throw new UnsupportedOperationException(
"Cannot remove an element from an enumeration.");
}
};
}
};
return RichIterable.from(iterable);
}
public static <A> RichIterable<A> from(final A[] xs) {
Iterable<A> iterable = new Iterable<A>() {
#Override
public Iterator<A> iterator() {
return new Iterator<A>() {
private int i = 0;
#Override
public boolean hasNext() {
return i < xs.length;
}
#Override
public A next() {
A x = xs[i];
i++;
return x;
}
#Override
public void remove() {
throw new UnsupportedOperationException(
"Cannot remove an element from an array.");
}
};
}
};
return RichIterable.from(iterable);
}
public boolean isEmpty() {
if (xs instanceof Collection) {
return ((Collection) xs).isEmpty();
}
for (A x : xs) {
return false;
}
return true;
}
public int size() {
if (xs instanceof Collection) {
return ((Collection) xs).size();
}
int size = 0;
for (A x : xs) {
size++;
}
return size;
}
public ArrayList<A> toArrayList() {
ArrayList<A> ys = new ArrayList<A>();
for (A x : xs) {
ys.add(x);
}
return ys;
}
public <B> RichIterable<B> map(F1<A, B> f) {
List<B> ys = new ArrayList<B>();
for (A x : xs) {
ys.add(f.apply(x));
}
return RichIterable.from(ys);
}
public RichIterable<A> filter(F1<A, Boolean> pred) {
List<A> ys = new ArrayList<A>();
Arrays.asList();
for (A x : xs) {
if (pred.apply(x)) {
ys.add(x);
}
}
return RichIterable.from(ys);
}
public boolean exists(F1<A, Boolean> pred) {
for (A x : xs) {
if (pred.apply(x)) {
return true;
}
}
return false;
}
public boolean forall(F1<A, Boolean> pred) {
for (A x : xs) {
if (!pred.apply(x)) {
return false;
}
}
return true;
}
public Maybe<A> find(F1<A, Boolean> pred) {
for (A x : xs) {
if (pred.apply(x)) {
return Just.of(x);
}
}
return Nothing.value();
}
public String mkString(String beg, String sep, String end) {
Iterator<A> i = xs.iterator();
if (!i.hasNext()) {
return beg + end;
}
StringBuilder sb = new StringBuilder();
sb.append(beg);
while (true) {
A e = i.next();
sb.append(e.toString());
if (!i.hasNext()) {
return sb.append(end).toString();
}
sb.append(sep);
}
}
public String mkString(String sep) {
return mkString("", sep, "");
}
public String mkString() {
return this.mkString(", ");
}
public Iterable<A> getRaw() {
return xs;
}
#Override
public Iterator<A> iterator() {
return xs.iterator();
}
}

Categories