300 likes | 409 Views
Practice Session 5. Java: Packages Collection Classes Iterators Generics Design by Contract Test Driven Development JUnit. Java Packages. What is Package? Way to group related class( es ) and interface(s) into one unit Package is basically a folder . Benefits? Code organization
E N D
Practice Session 5 Java: Packages Collection Classes Iterators Generics Design by Contract Test Driven Development JUnit
Java Packages • What is Package? • Way to group related class(es) and interface(s) into one unit • Package is basically a folder. • Benefits? • Code organization • All classes/interfaces related to one topic, are put under same package name. • Allows us to resolve conflicts between class names • By splitting the same name classes into two different packages. • Controlling class visibility • protected classes are visible to other classes inside the package only • Not visible to other packages, when imported.
MyTest Outs1 Print2.java Print1.java Java Packages • Declaration: • Declared at beginning of class file. • Syntax: package PackageName; • Example: • Folder: Package MyTest • Sub-folder: Package Outs1 • File: Class Print1.java • File: Class Print2java • Sub-folder: Package Outs2 • File: Class Print1.java Outs2 Print1.java
Java Packages • How to use them? • Use of absolute path of class: • Example: MyTest.Outs1.Print1 p1; • Using import keyword: • Import class: import MyTest.Outs1.Print1; • Import all classes under package: import MyTest.Outs1.*; • Object declaration: Print1 p1;
Java Collection • What is it? • A (huge)package of classes: • import java.util.Collection; • Contains useful data structures: • LinkedList • Stack • ArrayList • Vector • TreeSet • PriorityQueue • And much more… Full API: http://docs.oracle.com/javase/6/docs/api/java/util/Collection.html
Collection Iterator • All java.util.Collection data structures return an iterator to their elements. • Iterator commands: • booleanhasNext() • Returns true if there is a next element • Object next() • Returns the next object element/advances the iterator • void remove() • Optional operator / not all iterators implement it • Removes the element returned by next
Using the Iterator • Example: • Print all Collection object elements: • Code: static void printAll (Collection<Integer> coll) {Iterator<Integer>iter = coll.iterator( ); //returns iterator while (iter.hasNext( )) { //checks if has nextSystem.out.println(iter.next( ) ); //returns object } }
Generics • What are they? • Generic data structures are data structures that allows the use of any object type. • Explicitly declare what object type the data structure is going to use upon declaration, to help finding errors at compilation time. • How? • java.util.Collection.Stack<Object-Type> stk; • Examples: • A Stack that holds Integer objects. • java.util.Stack<Integer> intStack; • A LinkedList holding Student objects: • java.util.Collection.LinkedList<Student> studentList;
Generics Example Stack<Cow> stackOfCows = new Stack<Cow>()Stack<Float> stackOfFloat = new Stack<Float>() Cow cow = new Cow()stackOfCows.push(cow);stackOfFloat.push(cow);
Design by Contract(DBC) • What? • An approach for designing software. • Expresses contract between specification and implementation. • An agreement between two parties: client and supplier. • Why? • Trustworthy documentation. • Strong support for debugging. • Facilitate code reuse. • Condition Types in DbC: • Preconditions • Things that must be true before invoking a method • No conditions on after invocation. • Postconditions • Things that must be true after invoking a method • No conditions on before invocation • Invariants • things that must be true before and after any method is invoked • Must be true immediatelyafterconstruction.
Design by Contract Example public interface MyCollection { /** * Remove obj from the collection * * @require !( obj == null ) * * @ensure !contains( obj ) */ public void remove( Object obj ); Precondition disallows null argument. Postconditionvarifies that method removes ALL occurrences of obj /** * @invariant size() >= 0 */ public interface Queue { Assures queue size >= 0 always!
Design by Contract Principles • Separate queries from commands • Separate basic queries from derived queries. • For each derived query, write a postcondition that specifies what result will be returned, in terms of one or more basic queries. • For each command, write a postcondition that specifies the value of every basic query. • For every query and command, decide on a suitable precondition. • Write invariants to define unchanging properties of objects.
PRINCIPLE 1: separate commands and queries Commands public void add( Object o ); public void remove(); //just a command - no result Queries public int size(); public Object head(); public boolean isEmpty();
PRINCIPLE 2: separate basic queries and derived queries The choice of basic queries can change as we develop contracts Basic queries public int size(); public Object head(); Derived queries public boolean isEmpty(); -- we can derive isEmpty() from size()
PRINCIPLE 3: specify derived queries in terms of basic queries /** * Is the queue empty? * * @ensure return == ( size() == 0 ) */ public booleanisEmpty(); -- if we know the value of size(), we also know -- the value of isEmpty()
PRINCIPLE 4: specify postcondition for commands in terms of basic queries /** * The first element in the queue * * @require size() >= 1 * @ensure return == elements().get(0) */ public Object head(); postcondition uses basic query .get() for its implementation
PRINCIPLE 5: add preconditions where appropriate /** * The first element in the queue * * @require size() >= 1 */ public Object head(); It wouldn’t make the software better to pretend that an empty queue has a head element.
PRINCIPLE 6: specify invariant properties /** * @invariant size() >= 0 */ public interface Queue { Aim for properties that: - help readers build correct conceptual model
Test Driven Development (TDD) • What? • Test cases are first implemented and only then the code necessary to pass these tests are implemented. • Why? • Code is ensured to be working perfectly without any bugs! • Main tool in java: JUnit
Junit - Assert methods • Each assert method has parameters like these: message, expected-value, actual-value • assertTrue(String message, Boolean test) • assertFalse(String message, Boolean test) • assertNull(String message, Object object) • assertNotNull(String message, Object object) • assertEquals(String message, Object expected, Object actual) (uses equals method) • assertSame(String message, Object expected, Object actual) (uses == operator) • assertNotSame(String message, Object expected, Object actual) • Assert methods dealing with floating point numbers get an additional argument, a tolerance. (for rounding) • Each assert method has an equivalent version that does not take a message – however, this use is not recommended because: • messages helps documents the tests • messages provide additional information when reading failure logs
setUp/tearDown • setUp()/tearDown() • Functions which will run before and after each test. • Example usage: • setUp(): creating new objects • tearDown(): clearing data, resetting data. • If self destruction is good enough, there is no need to implement it. • setUpBeforeClass()/tearDownBeforeClass() • functions which will run exactly once before and after all the tests. • Can be used to initialize objects which will be used throughout the tests. • Changes done in first test, can be used as input data for the upcoming one.
JUnit tests for Counterclass • public class CounterTest { Counter counter1; public CounterTest() { } // default constructor • @Before protected void setUp() { // creates a (simple) test fixture counter1 = new Counter(); } • @Test public void testIncrement() {assertTrue(counter1.increment() == 1);assertTrue(counter1.increment() == 2); } • @Test public void testDecrement() {assertTrue(counter1.decrement() == -1); }} Note that each test begins with a brand new counter This means you don’t have to worry about the order in which the tests are run
Test Driven Development Cycle • Write the tests and for each Object Under Test (OUT): • Define interface • Define contract for each method • Specify invariant for the object, and for each method, pre and post-conditions. • Write the code so it will pass the test • Run tests • Refactor! • Improve the code, more efficient, less repetition, better looking.. • Repeat http://www.thecoadletter.com
Junit - Example • Interface: package spl.util; /** * All objects are of type T. Contents are ordered in Last-In-First-Out order. */ public interface Stack<T> { /** * add the object at the top of the stack. (This is a command.) * @paramobj * any non null T object to be added to the stack * @pre: none. * @post: this.isEmpty()==false * @post: this.pop(); this==@pre(this) * @post: this.pop()== @paramobj */ void push(T obj);
/** * remove the top object from the stack and returns it. * @return the topmost object on the stack * @throws Exception in case the stack is empty * @pre: this.isEmpty()== false; * @post: none. */ T pop() throws Exception; /** * @return True if the Stack is empty, or False if the Stack contains at * least one {@link Object}. * @pre: none. * @post: none. */ booleanisEmpty(); }
Create Class StackImpl package spl.util; public class StackImpl<T> implements Stack<T> { public void push(T obj) { } public T pop() throws Exception { return null; } public booleanisEmpty() { return false; } }
Creating a Test Case package spl.util; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; public class StackImplTest { Stack<Integer> stack; @Before public void setUp() throws Exception { this.stack = new StackImpl<Integer>(); } @After public void tearDown() throws Exception { } Before -> run before each test After-> run after each test
@Test public void testPush() { fail("Not yet implemented"); } @Test public void testPop() { fail("Not yet implemented"); } @Test public void testIsEmpty() { assertEquals(true, stack.isEmpty()); } } • What happens when we run the tests? • All 3 tests fail: • testPush and testPop because the methods are not implemented. • testIsEmpty since isEmpty returns false, even though the stack is empty.
Add implementation to isEmpty() to pass the tests. • Implement other tests and add the implementation of the methods they test to pass them. • Change the interface to include public void remove() and public T top() in addition to pop(), and implement pop() using remove and top, to separate queries from commands. • And so on….