Part 4~

Introduction to object-oriented programming

  • A class defines the attributes of objects, i.e., the information related to them like what the object has and is made up of(instance variables) that specifies internal state of object, and their commands, i.e., their methods. The values of instance (i.e., object) variables define the internal state of an individual object, whereas methods define the functionality it offers.

  • A method is a piece of source code written inside a class that’s been named and has the ability to be called. A method is always part of some class and is often used to modify the internal state of an object instantiated from a class.

  • An object is always instantiated by calling a method that created an object, i.e., a constructor by using the new keyword.

  • Each object created from the Person class has a name and an age. Variables defined inside a class are called instance variables, or object fields or object attributes.

public class Person {
    private String name;
    private int age;
}
  • The keyword private means that the variables are “hidden” inside the object. This is known as encapsulation. “variableName: variableType” The minus sign before the variable name indicates that the variable is encapsulated (it has the keyword private). -name:String and -age:int in Person class

  • When defining constructor, it’d be convenient to pass values ​​to the variables of that object as it’s being created. For example, when creating a new person object, it’s useful to be able to provide it with a name. This is achieved by defining the method that creates the object, i.e., its constructor. The constructor is defined after the instance variables.

public class Person {
    private String name;
    private int age;

    //constructor sets the age of the object being created to 0, 
    // and the string passed to the constructor as a parameter as its name:
    public Person(String initialName) {
        this.age = 0;
        this.name = initialName;
    }

    //method is below constructor
    public void printPerson() {
        System.out.println(this.name + ", age " + this.age + " years");
}

    //same result as printPerson() method
    public String toString() {
    return this.name + ", age " + this.age + " years";
}
    // returns something unlike void method
    //getter method
    public int getAge() {
    return this.age;
}

    //getter method
    public String getName() {
    return this.name;
}

}
  • The constructor’s name is always the same as the class name.

  • The constructor is also provided, as a parameter, the name of the person object to be created. The parameter is enclosed in parentheses (). The parentheses that contain optional parameters are followed by curly brackets. In between these brackets is the source code that the program executes when the constructor is called (e.g., new Person (“Ada”)).

  • Constructor contains the expression this.age = 0. This expression sets the instance variable age of the newly created object (i.e., “this” object’s age) to 0. The second expression this.name = initialName likewise assigns the string passed as a parameter to the instance variable name of the object created.

  • A method is written inside of the class beneath the constructor. The method name is preceded by public void, since the method is intended to be visible to the outside world (public), and it does not return a value (void).

  • The static modifier indicates that the method in question does not belong to an object and thus cannot be used to access any variables that belong to objects. So just public void. Going forward, methods will not include the static keyword if they’re used to process information about objects created from a given class. If a method receives all the variables whose values ​​it uses as parameters, it can have a static modifier.

  • The method printPerson contains code that makes use of the instance variables name and age. Instance variables are referred to with the prefix this.

  • Void means that the method does not return a value. If we want the method to return a value, replace the void keyword with the type of the variable to be returned. In the following example, the Teacher class has a method grade that always returns an integer-type (int) variable (in this case, the value 10). The value is always returned with the return command:

public class Teacher {
    public int grade() {
        return 10;
    }
}
  • The method above returns an int type variable of value 10 when called. For the return value to be used, it needs to be assigned to a variable. This happens the same way as regular value assignment, i.e., by using the equals sign:
public static void main(String[] args) {
    Teacher teacher = new Teacher();

    int grading = teacher.grade();

    System.out.println("The grade received is " + grading);
}
  • very good example of boolean:
public class Person {
    // ...

    public boolean isOfLegalAge() {
        if (this.age < 18) {
            return false;
        }

        return true;
    }
    //The method could have been written more succinctly in the following way:
    public boolean isOfLegalAge() {
        return this.age >= 18;
    }
}
  • Situations exist when we only want to know name of an object or just 1 instance variable, instead of printing all instance variables in a void print method. So use getter methods like getAge() or getName().

  • Creating a method for printing the object with printPerson method is not ideal. A preferred way is to define a method for the object that returns a “string representation” of the object. The method returning the string representation is always toString in Java:

public String toString() {
    return this.name + ", age " + this.age + " years";
}

public String toString(){
    return "My name is " + this.lastName +", " + this.firstName + " " + this.lastName;
}
  • The toString functions as printPerson does. However, it doesn’t itself print anything but instead returns a string representation, which the calling method can execute for printing as needed like this:
System.out.println(antti); // same as System.out.println(antti.toString());
System.out.println(pekka); // same as System.out.println(pekka.toString());
  • In principle, the System.out.println method requests the object’s string representation and prints it. The call to the toString method returning the string representation does not have to be written explicitly, as Java adds it automatically. When a programmer writes: System.out.println(antti); Java extends the call at run time to the following form: System.out.println(antti.toString());

  • If the method’s only purpose is to set a value to an instance variable, then it’s named as setVariableName. Value-setting methods are often called “setters”:

public class Person {
    private String name;
    private int age;
    private int weight;
    private int height;

    public Person(String initialName) {
        this.age = 0;
        this.weight = 0;
        this.height = 0;
        this.name = initialName;
    }
    //setter method
    public void setHeight(int newHeight) {
        this.height = newHeight;
    }
    //or
    public void setHeight(int height) {
        this.height = height;
    }
    //setter method
    public void setWeight(int newWeight) {
        this.weight = newWeight;
    }
    public double bodyMassIndex() {
    double heigthPerHundred = this.height / 100.0;
    return this.weight / (heigthPerHundred * heigthPerHundred);
    }
}
  • Calling internal method:
public String toString() {
    return this.name + ", age " + this.age + " years, my body mass index is " + this.bodyMassIndex();
}

Objects in a list

  • 3 ways to print objects in a list:
`ArrayList<String> names = new ArrayList<>();
names.add("Betty Snyder");
names.add("Frances Spence");

// 1. while loop
int index = 0;
while (index < names.size()) {
    System.out.println(names.get(index));
    index = index + 1;
}

// 2. for loop with index
for (int i = 0; i < names.size(); i++) {
    System.out.println(names.get(i));
}
System.out.println();

// 3. for each loop (no index)
for (String name: names) {
    System.out.println(name);
}
  • Strings are objects. Handling objects in a list is not really different in any way from the previous experience we have with lists. The essential difference is only to define the type for the stored elements when you create the list.
//creating list to store Person type object
ArrayList<Person> persons = new ArrayList<>();

// a person object can be created first
Person john = new Person("John");
// and then added to the list
persons.add(john);

// person objects can also be created "in the same sentence" that they are added to the list
persons.add(new Person("Matthew"));
persons.add(new Person("Martin"));

for (Person person: persons) {
    System.out.println(person);
}

// Read the names of persons from the user
while (true) {
    System.out.print("Enter a name, empty will stop: ");
    String name = scanner.nextLine();
    if (name.isEmpty()) {
        break;
    }
    // Add to the list a new person
    // whose name is the previous user input
    persons.add(new Person(name));
}
  • Multiple constructor parameters:
public class Person {

    private String name;
    private int age;
    private int weight;
    private int height;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        this.weight = 0;
        this.height = 0;
    }

    // methods
}
  • If we want to query the user for this kind of object, they must be asked for each parameter separately. In the example below, name and age parameters are asked separately from the user.
// Read person information from the user
while (true) {
    System.out.print("Enter name, empty will end: ");
    String name = scanner.nextLine();
    if (name.isEmpty()) {
        break;
    }

    System.out.print("Enter the age of the person " + name + ": ");

    int age = Integer.valueOf(scanner.nextLine());

    // We add a new person to the list.
    // The person's name and age were decided by the user
    persons.add(new Person(name, age));
}
  • If the name and age were separated by a comma, or in a specific format other than line by line:
Scanner scanner = new Scanner(System.in);
ArrayList<Person> persons = new ArrayList<>();

// Read person information from the user
System.out.println("Enter the person details separated by a comma, e.g.: Randall,2");
while (true) {
    System.out.print("Enter the details, empty will stop: ");
    String details = scanner.nextLine();
    if (details.isEmpty()) {
        break;
    }

    String[] parts = details.split(",");
    String name = parts[0];
    int age = Integer.valueOf(parts[1]);
    persons.add(new Person(name, age));
}

// Print the number of the entered persons, and the persons themselves
System.out.println();
System.out.println("Total number of persons: " + persons.size());
System.out.println("Persons: ");

for (Person person: persons) {
    System.out.println(person);
}
  • Books example:
public class Books {
    private String title;
    private int pubYear,pages;
    
    public Books(String title, int pages, int year){
        this.title = title;
        this.pubYear = year;
        this.pages = pages;
            
    }
    public String getTitle(){
        return this.title;
    }
    public int getPages(){
        return this.pages;
    }
    public int getPubYear(){
        return this.pubYear;
    }
    public String toString(){
        return this.title +", " + this.pages + " pages, " + this.pubYear;
    }
}

import java.util.ArrayList;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        
        // implement here the program that allows the user to enter 
        // book information and to examine them
        ArrayList<Books> list = new ArrayList<>();
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.println("Title:");
            String title = scanner.nextLine();
            if(title.isEmpty()){
                break;
            }
            System.out.println("Pages:");
            int pages= Integer.valueOf(scanner.nextLine());
            System.out.println("Publication year:");
            int year = Integer.valueOf(scanner.nextLine());
            
            list.add(new Books(title,pages,year));
        }
        System.out.println("What information will be printed?");
        String check = scanner.nextLine();
        for(Books a:list){
            if(check.equals("everything")){
                System.out.println(a.toString());
            }
            else{
                System.out.println(a.getTitle());
            }
        }

    }
}

Files and reading data

  • Convert from double to int using (int)

  • bufferedreader is simpler?

  • Reading a file is done using the Scanner-class by giving path for the file we want to read as a parameter to the constructor of the class. The path to the file can be acquired using Java’s Paths.get command, which is given the file’s name in string format as a parameter: Paths.get(“filename.extension”)

  • When the Scanner-object that reads the file has been created, the file can be read using a while-loop. The reading proceeds until all the lines of the file have been read, i.e., until the scanner finds no more lines to read. Reading a file may result in an error, and it’s for this reason that the process requires separate blocks - one for the try, and another to catch potential errors.

import java.util.Scanner;
import java.nio.file.Paths;

// in the program:

// we create a scanner for reading the file
try (Scanner scanner = new Scanner(Paths.get("file.txt"))) {

    // we read the file until all lines have been read
    while (scanner.hasNextLine()) {
        // we read one line
        String row = scanner.nextLine();
        // we print the line that we read
        System.out.println(row);
    }
} catch (Exception e) {
    System.out.println("Error: " + e.getMessage());
}
  • Reading lines to ArrayList and filtering numbers in a given range:
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;

public class NumbersFromAFile {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        ArrayList<String> list = new ArrayList<>();

        System.out.print("File? ");
        String file = scanner.nextLine();
        System.out.print("Lower bound? ");
        int lowerBound = Integer.valueOf(scanner.nextLine());
        System.out.print("Upper bound? ");
        int upperBound = Integer.valueOf(scanner.nextLine());

        int count = 0;

        // note new scanner named reader is made 
        try (Scanner reader = new Scanner(Paths.get(file))) {
            while (reader.hasNextLine()) {
                list.add(reader.nextLine());
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }

        for (String item : list) {
            int number = Integer.valueOf(item);
            if (number >= lowerBound && number <= upperBound) {
                count += 1;
            } else {
                continue;
            }
        }

        System.out.println("Numbers: " + count);
    }

}
  • If there is empty line in file and we want to skip emtpy lines:
try (Scanner scanner = new Scanner(Paths.get("henkilot.csv"))) {

    // we read all the lines of the file
    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();

        // if the line is blank we do nothing
        if (line.isEmpty()) {
            continue;
        }

        // do something with the data

    }
} catch (Exception e) {
    System.out.println("Error: " + e.getMessage());
}
  • Reading data in a specific format like .csv where data is separated by commas:
try (Scanner scanner = new Scanner(Paths.get("records.txt"))) {

    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();

        String[] parts = line.split(",");
        String name = parts[0];
        int age = Integer.valueOf(parts[1]);

        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}
  • Creating objects from data: Reading objects from a file should be isolated as a method.
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;

public class StoringRecords {

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        System.out.println("Filename:");
        String file = scan.nextLine();

        ArrayList<Person> records = readRecordsFromFile(file);
        System.out.println("Persons: " + records.size());
        System.out.println("Persons:");
        for (Person person : records) {
            System.out.println(person);

        }
    }

    public static ArrayList<Person> readRecordsFromFile(String file) {
        ArrayList<Person> persons = new ArrayList<>();

        // Write here the code for reading from file
        // and printing the read records
        try (Scanner scanner = new Scanner(Paths.get(file))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                String[]  parts = line.split(",");
                
                String name = parts[0];
                int age = Integer.valueOf(parts[1]);
                
                persons.add(new Person(name, age));
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }

        return persons;

    }
}