Interfaces - Exercises

Iterators

wouldn't it be nice to iterate through any Collection or array easily like this

class MainClass {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList();
        int[] ints = {100, 200, 300};

        for (int i = 0; i <= 50 ; i+=10)
            list.add(i);

        for (int elem : list)
            System.out.print(elem + "\t");


        System.out.println();
        for (int elem : ints)
            System.out.print(elem + "\t");

    }
}
0    10    20    30    40    50    
100    200    300

we can use the power of iterators

example

import java.util.Iterator;

class Main {
    public static void main(String[] args) {
        IntList list = new IntList();
        System.out.println(list);

        for (int i = 0; i <= 30; i+=10)
            list.add(i);

        System.out.println(list);              // IntList{size=4, capacity=10, elements=[0, 10, 20, 30]}

        //First way
        Iterator<Integer> it = list.iterator();
        while(it.hasNext())
            System.out.print(it.next() + " ,"); //Integer i = it.next();

        System.out.println();

        //2nd way, easier to use
        for (int elem : list)
            System.out.print(elem + " ,");

    }
}
IntList{size=0, capacity=10, elements=[]}
IntList{size=4, capacity=10, elements=[0, 10, 20, 30]}
0 ,10 ,20 ,30 ,
0 ,10 ,20 ,30 ,

our IntList now implements Iterable

As we can see we call the iterator function (another name would implement (override) the Iterator) and return an object of type Iterator

iterator has 2 functions

  • hasNext() return boolean

  • next() returns the next item

now we can use a for-each

🤔 How would write an iterator for a linkedList? Its not so difficult

Comparator

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;


class MainClass {
    public static void main(String[] args) {
        ArrayList<Point> list = new ArrayList();
        list.add(new Point(0,0));
        list.add(new Point(10,10));
        list.add(new Point(0,-10));
        list.add(new Point(0,-0));
        list.add(new Point(-10,-10));
        list.add(new Point(5,5));
        list.add(new Point(10,0));

        Collections.sort(list);

        System.out.println("========= sorting list ===========");
        for(Point point: list)
            System.out.println(point);


        // ========= sorting arrays ===========
        System.out.println("========= sorting arrays ===========");
        Point[] arr = new Point[7];
        arr[0] = new Point(0,0);
        arr[1] = new Point(10,10);
        arr[2] = new Point(0,-10);
        arr[3] = new Point(-10,-10);
        arr[4] = new Point(5,5);
        arr[5] = new Point(10,0);
        arr[6] = new Point(0,0);

        Arrays.sort(arr);

        for(Point point: arr)
            System.out.println(point);
    }
}
========= sorting list ===========
Point { x=-10.0, y=-10.0 }
Point { x=0.0, y=-10.0 }
Point { x=0.0, y=0.0 }
Point { x=0.0, y=0.0 }
Point { x=10.0, y=0.0 }
Point { x=5.0, y=5.0 }
Point { x=10.0, y=10.0 }
========= sorting arrays ===========
Point { x=-10.0, y=-10.0 }
Point { x=0.0, y=-10.0 }
Point { x=0.0, y=0.0 }
Point { x=0.0, y=0.0 }
Point { x=10.0, y=0.0 }
Point { x=5.0, y=5.0 }
Point { x=10.0, y=10.0 }

change in Point

  • implemented Comparable, now we can sort

    • overrided compareTo function

class Point implements Comparable<Point> {
    //...
    @Override
    public int compareTo(Point other) {
        //  First sort by Y
        //  Then  sort by X
        if (this.equals(other)) {
            return 0;
        }else if (y != other.y){
            return (y > other.y) ? 1 : -1;
        }else { //if (y == other.y)
            return (x > other.x) ? 1 : -1;
        }
    }
}

Test Question

Note: the answer can be much simpler but I trying to teach a few ideas

class Main {
    public static void main(String[] args) {
        StdDraw.setXscale(0, 100);
        StdDraw.setYscale(0, 100);

        PointContainer polygon1 = new PointContainer();
        polygon1.add(new Point(20,20));
        polygon1.add(new Point(80,20));
        polygon1.add(new Point(50,70));

        polygon1.sort();
        polygon1.close();

        System.out.println(polygon1);
        polygon1.draw();

        //use iterator
        for (Point p : polygon1)
            System.out.print(p + "\t");
    }
}
Polygon{size=4, capacity=10, elements=[Point { x=20.0, y=20.0 }, Point { x=80.0, y=20.0 }, Point { x=50.0, y=70.0 }, Point { x=20.0, y=20.0 }]}
Point { x=20.0, y=20.0 }    Point { x=80.0, y=20.0 }    Point { x=50.0, y=70.0 }    Point { x=20.0, y=20.0 }

or this

import java.util.ArrayList;

class MainClass {
    public static void main(String[] args) {
        ArrayList<PointContainer> polygons = new ArrayList<>();

        StdDraw.setXscale(0, 500);
        StdDraw.setYscale(0, 500);

        polygons.add(new PointContainer(new Point[]{new Point(229, 153), new Point(160,218), new Point(177,325), new Point(249,268)} )) ;
        polygons.get(0).sort().close();

        polygons.add(new PointContainer(new Point[]{new Point(249,268), new Point(177,325),new Point(269,336), new Point(349,283) } ));
        polygons.get(1).sort().close().setColor(0,255,0);

        polygons.add(new PointContainer(new Point[]{new Point(349,283), new Point(328,182),new Point(229,153), new Point(249,268) } ));
        polygons.get(2).sort().close().setColor(255,0,0); // remove sort to fix messed up polygon

        for (PointContainer p : polygons){
            p.draw();
            System.out.println(p);
        }
    }
}
Polygon{size=5, capacity=8, elements=[Point { x=160.0, y=218.0 }, Point { x=229.0, y=153.0 }, Point { x=249.0, y=268.0 }, Point { x=177.0, y=325.0 }, Point { x=160.0, y=218.0 }]}
Polygon{size=5, capacity=8, elements=[Point { x=249.0, y=268.0 }, Point { x=177.0, y=325.0 }, Point { x=269.0, y=336.0 }, Point { x=349.0, y=283.0 }, Point { x=249.0, y=268.0 }]}
Polygon{size=5, capacity=8, elements=[Point { x=229.0, y=153.0 }, Point { x=249.0, y=268.0 }, Point { x=328.0, y=182.0 }, Point { x=349.0, y=283.0 }, Point { x=229.0, y=153.0 }]}

we could also use

 public PointContainer sort() {
         Arrays.sort(elements); 
         return this;
    }

if we implement Comparator

import java.util.Comparator;
import java.util.Objects;

class Point implements Comparator<Point>, Comparable<Point> {
    public double x, y;

    //...

    @Override
    public int compare(Point p1, Point p2) {
        if (p1 == null && p2 == null) {
            return 0;
        }
        if (p1 == null) {
            return 1;
        }
        if (p2 == null) {
            return -1;
        }
        return p1.compareTo(p2);
    }


    @Override
    public int compareTo(Point other) {
        // euclidean distance
        if (this.equals(other))
            return 0;

        //same distance then check Ys
        if (distance(new Point(), this) == distance(new Point(), other)){
            if (y != other.y)
                return  y > other.y ? 1 : -1;
            else
                return  x > other.x ? 1 : -1;
        }

        //if distance is not the same
        return  (distance(new Point(), this) > distance(new Point(), other)) ? 1 : -1;
    }
}

or even doing this

public class PointContainer implements Iterable<Point>{
    //... add before


    public PointContainer sort() {
        Arrays.sort(elements, new Comparator<Point>() {
                @Override
                public int compare(Point p1, Point p2) {
                    if (p1 == null && p2 == null) {
                        return 0;
                    }
                    if (p1 == null) {
                        return 1;
                    }
                    if (p2 == null) {
                        return -1;
                    }
                    return p1.compareTo(p2);
                }
        });

        return this;
    }

    //==== add iterator =========
}
class Point implements Comparable<Point> {
    //now there is no compare(Point p1, Point p2)

    @Override
    public int compareTo(Point other) {
        // euclidean distance
        if (this.equals(other))
            return 0;

        //same distance then check Ys
        if (distance(new Point(), this) == distance(new Point(), other)){
            if (y != other.y)
                return  y > other.y ? 1 : -1;
            else
                return  x > other.x ? 1 : -1;
        }

        //if distance is not the same
        return  (distance(new Point(), this) > distance(new Point(), other)) ? 1 : -1;
    }
}

Exercise: Student and Grade

public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("moshe", 25));
        students.get(0).add(new Grade("infi", 95));
        students.get(0).add(new Grade("java", 100));

        //add more students

        Collections.sort(students);

        for (Student s : students)
            System.out.println(s);
    }

and get something like this

Student{name='moshe', age=25, avg_grades=97.66666666666667, grades=[{sub='infi', grade=95.0}, {sub='java', grade=100.0}, {sub='data structures', grade=98.0}]}
Student{name='aviv', age=28, avg_grades=87.66666666666667, grades=[{sub='infi', grade=100.0}, {sub='java', grade=65.0}, {sub='data structures', grade=98.0}]}
Student{name='rachel', age=23, avg_grades=85.0, grades=[{sub='infi', grade=80.0}, {sub='java', grade=75.0}, {sub='data structures', grade=100.0}]}

we are sorting by the grade average

We will need to make 2 classes

  • Grade

    • String subject

    • double grade

  • Student

    • static int rollno

    • String name

    • int age

    • List<Grade> grades

solution

class Main {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("moshe", 25));
        students.add(new Student("rachel", 23));
        students.add(new Student("aviv", 28));

        students.get(0).add(new Grade("infi", 95));
        students.get(0).add(new Grade("java", 100));
        students.get(0).add(new Grade("data structures", 98));

        students.get(1).add(new Grade("infi", 80));
        students.get(1).add(new Grade("java", 75));
        students.get(1).add(new Grade("data structures", 100));

        students.get(2).add(new Grade("infi", 100));
        students.get(2).add(new Grade("java", 65));
        students.get(2).add(new Grade("data structures", 98));

        Collections.sort(students);

        for (Student s : students)
            System.out.println(s);
    }
}    
Student{name='moshe', age=25, avg_grades=97.66666666666667, grades=[{sub='infi', grade=95.0}, {sub='java', grade=100.0}, {sub='data structures', grade=98.0}]}
Student{name='aviv', age=28, avg_grades=87.66666666666667, grades=[{sub='infi', grade=100.0}, {sub='java', grade=65.0}, {sub='data structures', grade=98.0}]}
Student{name='rachel', age=23, avg_grades=85.0, grades=[{sub='infi', grade=80.0}, {sub='java', grade=75.0}, {sub='data structures', grade=100.0}]}

we don't have to implement Iterator since we are using Java Arraylist

GUIs - Not on the test!

what else can we use interfaces for?

for GUIs

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class Main extends JFrame {
    public static void main(String[] args) {
        JFrame frame = new JFrame("My First GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300,300);
        JButton button1 = new JButton("Add 1");
        JButton button2 = new JButton("Add 5");

        frame.getContentPane().add(BorderLayout.NORTH, button1);
        frame.getContentPane().add(BorderLayout.SOUTH, button2);
        JLabel jlabel = new JLabel("you clicked me 0 times");
        frame.getContentPane().add(BorderLayout.CENTER, jlabel);

        final int[] counter = {0};



        // ============= important stuff ============
        // here we implement the ActionListener interface
        button1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("you clicked me " + ++counter[0] + " times");
                jlabel.setText("you clicked me " + counter[0] + " times");
            }
        });

        button2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("you clicked me " + (counter[0]+=5) + " times");
                jlabel.setText("you clicked me " + (counter[0]) + " times");
            }
        });

        frame.setVisible(true);
    }
}

ActionListener is an interface we implement add to the addActionListener() on a button

Last updated