Friday, June 3, 2016

Super basic object stuff

I am not going to rework this right now, I think it gets the main points across as is.

From a recent Reddit post:

What you are asking about is quite basic to object oriented programming. Let's start with the first point I'd like to make: PersonA and PersonB are exactly the same thing, except the data is different. However, they cannot be simple methods that return integer values, that will never fly. The values you're setting up are lost as soon as the methods end.
Instead, you want to create objects of type Person. You do this by creating a class called Person and setting up variables to represent the values you want. At its absolute most basic (and this isn't correct, it's just showing the idea) it would look like this:
public class Person {
    public int x;
    public int y;
    public int range;
}
This is more akin to what we used to call a struct in c. Ordinarily you'd have a lot more stuff in there, but adding that right now could inhibit understanding so I want to take this slowly.
With the above class you could do this in the class you've posted:
public static void main(String [] args) {
    Person a = new Person();
    a.x = 200;
    a.y = 100;
    a.range = 160;

    Person b = new Person();       
    b.x = 100;
    b.y = 400;
    b.range = 170;
After that, you could use 'a.x' or 'b.range' the same way you were originally trying to use 'xA' or 'rangeB'.
Remember when I said that I was just showing the basics? Well, objects are a lot more powerful than just bags of variables. Let's use just another couple of features.
First, let's make a 'constructor' for Person so you can slim down your code:
public class Person {
    ... //What you already have
    public Person(int newX, int newY, int newRange) {
        x = newX;
        y = newY;
        range = newRange;
    }
}
Now your main can do this:
Person a = new Person(200, 100, 160);
Isn't that nicer?
Next, let's add 'accessor' methods to Person. Accessors are also called 'getters' and there are good reasons to use them. Trust me on this, I'm on the train and don't have time to fully explain:
public class Person {
    ... //What you already have

    public int getX() {
        return x;
    }

    //Do the same thing for 'y' and 'range'
}
At this point, you could still do 'a.x = 5' or 'range = b.range'. We can prevent that by marking the variables as 'private'
public class Person {
    private int x;
    private int y;
    private int range;
    ... //what you otherwise already have
}
But wait! Now when I try to write a.x=5 I get some horrible error and everything is broken and the world is ending!
No, you just need 'setters', also known as modifiers to do the job for you:
public class Person {
    ... //Everything you already have
    public void setX(int newX) {
        x = newX;
    }
    // Follow the same pattern for y and range
}
Now the equivalent to 'int range = a.range' is 'int range = a.getRange()', and the equivalent of 'a.range = 50' is 'a.setRange(50)'.
There's a LOT more to OOP, we've really just scratched the surface. But just encapsulating your data in this way will go a long way towards making your programs more readable, maintainable and robust.
I have no doubt that questions are coming up in your mind. I tried to make this clear and left out a few niceties in the interest of getting it written quickly and not overloading you, but it's a lot to absorb. Please ask questions when you need clarification.

Sunday, November 15, 2015

There's a loop for each of us

This is one of the really useful additions to the Java language specifications.  It greatly simplifies many loop structures, eliminating a bunch of verbiage that we long thought was just part of the deal when writing code.

Let's meet what I hope will become a good friend of yours:  The enhanced for, also known as the 'for each' loop.

The for each loop structure is an enhancement that can be used to replace many of the standard for or while loops you would otherwise be writing.  It is extremely common to have to, for instance, go over the elements of an array or a collection, extract one element at a time, and perform operations on it.  Let's pretend that we have an ArrayList of Person objects, and we want to print a list of first and last names.

In the old days we might have written this (and if you don't understand why I use 'List' instead of 'ArrayList' see 'Good Practices: Coding to the Interface'):

public static void printPersonList1(List personList) {
    System.out.println("Using a 'while' loop the JDK 1.4 (and earlier) way:");
    Iterator iter = personList.iterator();
    while(iter.hasNext()) {
        Person p = (Person) iter.next();
        System.out.println(p.getFirstName() + " " + p.getLastName());
    }
}

Now, one improvement was the addition of 'Generics', which allowed us to simplify the code a bit by informing the compiler that our List and Iterator had to be of type Person:

public static void printPersonList2(List personList) {
    System.out.println("Using a 'while' loop with generics:");
    Iterator <Person> iter = personList.iterator();
    while(iter.hasNext()) {
        Person p = iter.next();
        System.out.println(p.getFirstName() + " " + p.getLastName());
    }
}

Now, you might be wondering why I did my demonstrations of old style code with while loops to demonstrate a better for loop.  This is mostly because the while loop syntax is better suited to running over an Iterator than an old style for loop was.  It could be done, but frankly it's not as clean.  You'll note I had to leave out the third term of the for loop because it only gets executed after the body of the loop is complete and I had to pre-seed with the first value:

public static void printPersonList3(List<Person> personList) {
    System.out.println("Using a 'for' loop with generics:");
    Person p = null;
    for(Iterator <Person> iter = personList.iterator(); iter.hasNext(); ) {
        p = iter.next();
        System.out.println(p.getFirstName() + " " + p.getLastName());
    }
}


Alternately, we could have skipped the Iterator altogether, which is really more in keeping with the natural usage of the old style for loop:

public static void printPersonList4(List<Person> personList) {
    System.out.println("Using a 'for' loop with no iterator:");
    Person p = null;
    for(int i = 0; i < personList.size(); i++) {
        p = personList.get(i);
        System.out.println(p.getFirstName() + " " + p.getLastName());
    }
}


OK, here's the actual example I'm trying to get across to you.  This is the 'enhanced for' loop, also knows as the 'for each':

But the for each loop construct went a lot further and made things much better:

public static void printPersonList5(List<Person> personList) {
    System.out.println("Using a 'for each' loop:");
    for(Person p:personList) {
        System.out.println(p.getFirstName() + " " + p.getLastName());
    }
}

Note how concise it is, with no extra stuff.  Get Person objects from this collection and run with it.  Using the enhanced for loop simplifies our code, letting us get on with the conceptual task at hand and saving our fingers from some typing.  It's extremely common to go over a collection of data and perform some task on every element, so why should we have to write it all out explicitly every time?  You can use for each loops on classes based on Collection and on arrays equally well, which means we're more likely to use it and get the code right the first time.

private static void printStringArray(String[] aList) {
    System.out.println("The enhanced for can also work on array types:");
    for(String s: aList) {
        System.out.println(s);
    }
    System.out.println();
}

It actually took me a while to get used to using this loop structure, because I spent so much time supporting code that had to run in 1.4 level JREs.  In order to ensure the best compatibility I was also compiling with a 1.4 JDK so I didn't have access to this feature.  I'll tell you what, I was really missing out.  My fingers are probably a couple of millimeters shorter than they should be because of all the wear and tear from the extra typing I did.  I for one am glad we have this loop available, and you probably should be, too.

View Code