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 + " ,");
}
}
import java.util.Arrays;
import java.util.Iterator;
public class IntList implements Iterable<Integer>{
/// we we did before
//add iterator
@Override
public Iterator<Integer> iterator() {
Iterator it = new Iterator() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < size;
}
@Override
public Integer next() {
return elements[currentIndex++];
}
};
return it;
}
}
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 booleannext()
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);
}
}
class Point implements Comparable<Point>{
public double x, y;
//=== constructors ===
//default constructor
Point() {
x = 0;
y = 0;
}
Point(double x, double y) {
this.x = x;
this.y = y;
}
//copy constructor
Point(Point p) {
x = p.x; // Since this is the same class I can access without getter/setter
y = p.y;
}
//=== static methods ===
public static double distance(Point a, Point b) {
double dist = Math.pow(a.x-b.x, 2) + Math.pow(a.y-b.y, 2);
return Math.sqrt(dist);
}
public String toString() {
return "Point {" + " x=" + x + ", y=" + y + " }";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return Double.compare(point.x, x) == 0 && Double.compare(point.y, y) == 0;
}
@Override
public int compareTo(Point other) {
// First sort by Y
// Then sort by X
// 0 is equal, 1 if this is larger, -1 if other is larger
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;
}
}
}
========= 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");
}
}
class Point implements Comparable<Point>{
public double x, y;
//...
// ================ Look Here ===================
@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;
}
}
package com.company;
import java.awt.*;
import java.util.Arrays;
import java.util.Iterator;
//Polyon
public class PointContainer implements Iterable<Point>{
private int size = 0; // shouldn't be public
private static final int DEFAULT_CAPACITY = 10;
private Point[] elements;
private Color color;
private String name = new String("");
//...
//added new constructor
public PointContainer(Point[] points) {
size = points.length;
elements = Arrays.copyOf(points, size);
setColor(0,0,255);
}
public PointContainer close() {
add(new Point(elements[0]));
return this;
}
// ========= This is what sorts ==================
public PointContainer sort() {
Arrays.sort(elements, 0, size); // can't use Arrays.sort(elements), since there are nulls
return this;
}
// ========= until here ==================
//==== add iterator =========
@Override
public Iterator<Point> iterator() {
Iterator it = new Iterator() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < size;
}
@Override
public Point next() {
return elements[currentIndex++];
}
};
return it;
}
}
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);
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Student implements Comparable<Student>{
static int rollno = 0;
String name;
int age;
List<Grade> grades; //our class
Student(String name,int age){
this.rollno= ++rollno;
this.name=name;
this.age=age;
grades = new ArrayList<>();
}
public Student add(Grade new_grade){
grades.add(new_grade);
return this;
}
public double avg_grades(){
double sum = 0;
for (Grade g : grades)
sum += g.grade;
return sum/grades.size();
}
public int compareTo(Student other){
//sort students by average
if(grades.size()==0 || (avg_grades() == other.avg_grades()))
return 0;
else if(avg_grades() > other.avg_grades())
return -1;
else
return 0;
}
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + ", "+ "avg_grades=" + avg_grades() + ", grades=" + grades + '}';
}
}
public class Grade {
public String subject;
public double grade;
public Grade(String subject, double grade) {
this.subject = subject;
this.grade = grade;
}
@Override
public String toString() {
return "{" + "sub='" + subject + '\'' + ", grade=" + grade +'}';
}
}
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