Code 6
Code 6
>
Chapter 3
Structured Code
>
Programs used to be written like this 1 t=0 t=0; i=1 2 i=1 yes 3 if i>n goto 7 i>n? 4 t=t+i no t=t+i; i=i+1 5 i=i+1 6 goto 3 print t 7 print t This is spaghetti programming, and the flow diagram is no better (except that it helps follow the strands)
Code p2
Ian Holyer
COMS12100
Code p1
Structuring
>
The idea with structured programming is that you say what you mean; the program is readable: total = 0; for (i = 1; i <= n; i = i+1) { total = total + i; } print (total); It is is still possible to make a spaghetti mess No language is readable unless you are fluent Clean structured code is clearer than flow diagrams
Code p3
Data structures: ways of grouping data Code structures: ways of grouping code so it is as easy to execute a group of lines as a single line The word code is unfortunate, because it implies something difficult to read, but we are stuck with it Structured programming is old (Algol, Pascal). It is used in C & Java for the medium scale We will look at: arrays for grouping data methods for grouping code loops for repeating code
Code p4
Java Arrays
> > > >
Using Arrays
>
>
This is the commonest Java way of grouping a variable sized collection of similar items Java also has a lot of library classes for storing other kinds of collections such as lists, trees, tables Arrays are efficient; they match (serial) hardware, but have fixed limits The limits of an array are fixed dynamically when you create it, and if you want an array which expands as needed, you can use (e.g.) java.util.ArrayList In Java, arrays are objects with a directly accessible length field, and indexable data, and bounds checks
Code p5
>
>
Java
Java
Example: substrings
>
There are two common conventions in everyday life Counting from 1 and Measuring from 0 as with a ruler
1 1 1 2 3 4 5 0 1 2 3 4 5
The substring() method of the String class lets you extract a substring between two positions
s= 0 1 s 1 p 2 o 3 t 4 s 5 p o t
s.substring(1,4)
In programs, it is usually better to measure positions between items (as with birthdays!) The example has 6 positions numbered from 0 to 5 Indexing arrays from 0 supports the positional idea
Code p7
> >
This convention avoids off-by-1 errors, special case problems etc. The explanations of substring in books and online documentation are often poor (and the substring method in JDK version 1.2 had a bug!)
Code p8
Java
Java
While Loops
>
For Loops
>
>
>
The test is done before each execution of the loop statement(s), so there may be zero iterations
>
Java
Code p9
Java
Example: searching
> >
Find a name in an array of strings The problem is too subtle to use for, so use while
int i = 0, pos = -1; boolean found = false; while (i < names.length && ! found) { if (names[i].equals(name)) { found = true; pos = i; } (don't forget this!) i++; }
> >
It means: "for each s in the array names" It is short for this (so use it when you don't need i)
for (int i = 0; i < names.length; i++) { String s = names[i]; ... }
Java
Code p11
Java
Code p12
Methods
> >
In Java, procedures are called methods A method is defined by return type argument types int process(String s, int n) { actions; argument names } Every method is defined inside a particular class Classes group code and associate it with data
Code p13
> >
>
Java
Java
Code p14
Library Methods
> >
To have normal non-static methods and global data, you need a program object (in general, a current object)
class Calculator { double value; (global "register") public static void main(String[] args) { ... Calculator program = new Calculator(); String result = program.run(args); } ... String run(String[] args) { ... } }
Java Code p15 Java
Most library methods are associated with objects These examples are from the String class and are called on a String object
String s = "spots"; int n = s.length(); String s2 = s.substring(1,4); boolean b = s2.equals("pot"); char c = s.charAt(0); boolean plural = s.endsWith("s"); char[] cs = s.toCharArray();
Code p16
Static Methods
> >
Recursive Methods
>
Some methods don't have a current object These are the ones declared as static
class Prog { public static void main(String[] args) { ... }
>
> >
The system calls main() with no current object There are common static methods in java.lang
Math.sqrt(2.0) Character.isUpperCase('C') Integer.parseInt("42")
Java
Code p17
Java
Code p18
Debugging
> > > > >
>
A bug is a mistake in your program, and everybody is human, so you will produce a lot of them Debugging is one of the most important skills for a programmer, yet it is often not covered well in books It is true that you learn it mostly by experience, e.g. in the lab, but a few rules and tricks can go a long way Debugging can take a very, very, very long time If you are bad at it, it can make you 10 or 100 times slower than other programmers, e.g. so that it is impossible for you to do a weekly assignment on time Your competence at debugging is critical, so think about it and pay some attention to it
Code p19
> >
>
There is one rule of debugging above all others - you should never forget it and never break it: Never write more than a handful of lines of code before re-compiling and re-running your program If you are a weaker programmer, you should write fewer lines of code at a time The reason is simple: if it turns out that there is a bug, you know it is in those few lines of code, you just wrote them so you are very familiar with them, and you can catch the bug really quickly Also, the chances of two interacting bugs is very low
Code p20
> >
This is nearly as important as rule one: Design your program in small pieces (methods and, later on, classes) Each piece needs to to carry out some well-defined, easy to understand task The reason is essentially the same as before: if a bug emerges which is not in the lines you just wrote, at least it is in the few lines of a self-contained method
>
If you can't spot a bug straight away, you need to treat it as a detective problem and track it down That means understanding and checking what the program is doing, to find out where it is going wrong Problem halving is the main detective principle: Find a way to split the search into two parts, and a way of testing which of the two parts contains the bug For example, this might be "does the program go wrong before or after the moment when..." or "is the bug inside or outside the code that deals with..."
Code p21
Code p22
Debugging by printing
>
Testing
>
> >
It is a crude technique, but it works in all languages , on all platforms, and in all IDEs It is really useful to define a method for yourself, to abbreviate the print statements and switch them on/off
void p(String s) { if (! printing) return; System.out.println(s); }
Code p23
Modern ("agile") development techniques begin with testing, but it is not about how much testing to do: - it is impossible to test everything - it is suicidal to test nothing So how much testing you do is down to experience The real issue is your attitude to testing and the approach you take Let's look at the first assignment (Grade) as an example, and see how programmers would have tested it in the past, and how they should test it now
Code p24
Unit Testing
> >
The new, right way to do testing is called unit testing The program tests itself, e.g. when it has no args:
> java Grade OK
> >
This involves boring typing, and checking by eye: Alan Turing said "There need be no real danger of it ever becoming a drudge, for any processes that are quite mechanical may be turned over to the machine itself." (1946, proposal for first computer)
Code p25
To get this to work well, you need to design the way the testing is going to work It may change the design of the program, so testing needs to be part of the program design from the start In fact the suggestion that there should be a run method which takes the arguments and returns a string was made with testing in mind
Code p26
It is convenient for the first string to contain all the command line arguments On the other hand, the main method is passed an array of strings, after they have been chopped up by the OS So, the check method will need to split the string
Code p27
>
The main method cannot see the global report variable in the program object, because there is no program object when main is running, so the test method must return the report variable to main:
String test() { check("50", "Lower second class"); ... return report; }
The main method either calls run, or calls test (which calls check, which calls run)
public static void main(String[] args) { Grade program = new Grade(); String r; if (args.length == 0) r = program.test(); else r = program.run(args); System.out.println(r); }
>
Strictly speaking, if the result is an error message, it should be printed on System.err, and System.exit(1) should be called
Code p30
Code p29
Regression Testing
>
>
There is an old technique called regression testing: keep old tests and re-run them later, which used to be very cumbersome to do You can see that it is now built in to unit testing The point is that when you add a feature or fix a bug, you very often break something that used to work Unit testing guards against this: every time you add a feature or fix a bug (in fact every time you recompile the program) you should test it, so you know which five-line change contains the bug How much testing should you do? Enough so that if the testing succeeds, you are confident that your program is working properly
Code p31
The next step in modern development is to use this approach to testing to good advantage, to avoid unnecessary documentation and meetings: - write some tests before you start: these can take the place of specification and design documents, explaining what the program is supposed to do - add more tests as you program, to illustrate the features added or issues that crop up, and to take the place of team meetings and progress reports - when you can't think of any more tests, and all the tests succeed, then you know you have finished!
Code p32
Refactoring
> > > >
Simplicity
>
>
Unit testing leads to a technique called refactoring, which really just means changing your mind When you add a feature, you realise that your program design isn't good enough, and you need to "rewrite" it Programmers have always rewritten their programs, but now it is an officially allowed technique It works, because there is now a simple check that the program is back together and working properly again, namely when the testing succeeds once more The tests may need to be rewritten alongside the rest of the program and big refactoring steps may need to be broken down into stages
Code p33
>
>
Unit testing and refactoring lead to another feature of modern development, namely the advice: use the simplest thing which works properly The idea is that if you have a need for a feature today, use the simplest approach that gives you that feature, and don't spend lots of time and effort designing your program to be future-proof, in ways which may never be needed anyway Instead, trust yourself to be able to refactor your program to make it more sophisticated so that further features can be added, if and when that is needed
Code p34