# Why Interfaces?
Suppose you have a collection of students based on the following class
```java
package studentchooser;
/**
*
* @author aballantyne
*/
public class Student {
private String forename;
private String surname;
private int age;
/**
* @return the forename
*/
Student(String forename, String surname, int age){
this.forename = forename;
this.surname = surname;
this.age = age;
}
public String print(){
return this.forename + " " + this.surname + ", " + this.age;
}
public String getForename() {
return forename;
}
/**
* @param forename the forename to set
*/
public void setForename(String forename) {
this.forename = forename;
}
/**
* @return the surname
*/
public String getSurname() {
return surname;
}
/**
* @param surname the surname to set
*/
public void setSurname(String surname) {
this.surname = surname;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
```
You want to print out the students according to certain criteria, for example those under 16 or those with the surname Bloggs.
One possible solution is shown below
# "Bad" Solution
```java
public class StudentChooser {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
List<Student> students = Arrays.asList(
new Student("Joe", "Bloggs", 17),
new Student("Emily", "Bronte", 15),
new Student("Mo","Farah",11),
new Student("Jenny", "Bloggs", 15)
);
printAll(students);
printUnder16(students);
}
public static void printAll(List<Student> students)
{
for (Student student: students)
{
System.out.println(student.toString());
}
}
public static void printUnder16(List<Student> students)
{
for (Student student: students)
{
if (student.getAge()<16)
System.out.println(student.toString());
}
}
}
```
You can see there is a lot of duplication here. You could imagine having to write a number of methods printSurnameBloggs(), printUnder 21() etc.
We need a way to abstract out the common code. Java provides such way with interfaces.
# Better Solution with Interfaces

```java
YUML: https://yuml.me/diagram/plain/class/draw
[<<Choice>>]^-.-[StudentChooser]
```
* Notice there is now an interface called Choice added. The interface has one method test() to be overriden
* Notice the StudentChooser class has two methods, main() and printChoice()
* printChoice() takes an additional parameter defined according to the Choice interface. We use this "choice" to determine what we are going to filter.
```java
package studentchooser;
import java.util.Arrays;
import java.util.List;
interface Choice{
boolean test(Student s);
}
public class StudentChooser {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
List<Student> students = Arrays.asList(
new Student("Joe", "Bloggs", 17),
new Student("Emily", "Bronte", 15),
new Student("Mo","Farah",11),
new Student("Jenny", "Bloggs", 15)
);
printChoice(students, new Choice() {
@Override
public boolean test(Student s) {
return (s.getAge() <16);
}
});
printChoice(students, new Choice() {
@Override
public boolean test(Student s) {
return (s.getSurname().equals("Bloggs"));
}
});
}
public static void printChoice(List<Student> students, Choice choice)
{
for (Student student: students)
{
if(choice.test(student)) System.out.println(student.print());
}
}
}
```
# Exercise
1. Add a statement to the above code to print out all the people aged 15
2. Add a field to the student class to record gender.
3. Add a statement to the code to print out all students with gender = "m"
4. Add a statement to the code to print out all students under 16 with gender = "f"
# Lambda Expressions
* You might find your IDE suggests changing your code to include Lambda expressions. You can learn more about them here.