Unit 01 - Java Review - Functional Interfaces - Unit Tests PDF
Document Details
Uploaded by ComfortingFeministArt7817
University of Essex
2024
Dr Tasos Papastylianou
Tags
Summary
This document previews the CE303 Advanced Programming Unit 1 materials for the University of Essex. It includes an overview of the module, its background, and details about the upcoming content of the unit. It touches on Java basics, review, functional interfaces and unit tests, suitable for undergraduate students.
Full Transcript
CE303 Advanced Programming Unit 1 (14th Oct 2024) Java review. Functional interfaces. Unit tests. Module Supervisor: Dr Tasos Papastylianou ([email protected]) Welcome to CE303: A...
CE303 Advanced Programming Unit 1 (14th Oct 2024) Java review. Functional interfaces. Unit tests. Module Supervisor: Dr Tasos Papastylianou ([email protected]) Welcome to CE303: Advanced Programming * Let’s start with some introductions! * Dr(2) Tasos Papastylianou (BSc, MBChB, MSc, DPhil (Oxon), LRSM, FHEA) Research Fellow in Health Informatics (i.e. Probationary Lecturer in CSEE) Institute of Public Health and Wellbeing, University of Essex Email: [email protected] Academic Office Hours: Tuesdays, 10:00-12:00 What about yourself? If you have a phone or laptop, go to http://PollEv.com/ce303 Note: this poll is anonymous; if it asks you to ‘register’, just press ‘skip’ CE303 Overview Functional Interfaces Unit Tests Threads and Concurrency I/O and Serialisation Sockets Web requests Generics Collections Streams Optional Program Optimisation & Design patterns Functional Programming (Haskell) Module background Expected to have done some Java programming previously and be comfortable with the basics Occasionally compare how other languages do things, but main focus is Java Not an introductory module! (builds on last 2 years’ experience!) If you need a refresher beyond today – moodle reading list. Learn how to make Java do some cool stuff! (also Haskell towards the end – not assessed) Slide 7/69 Module organisation Weekly lectures (2h) and labs (2h) Labs: STEM 4.2A+B + CSEE Lab 7 Total mark for module consists of: 2 MCQ Progress Tests (Weeks 7 and 11) (20% each) One programming assessment in Java (60%: 40% code, 20% report) No Summer exam. Moodle Unit content (regrettably) still being updated. Will try to put materials as much in advance as possible. Many facilities (Forums, MoodleOverflow, Chat, Feedback) Anki! 🎉 Slide 8/69 Module organisation (continued) Labs Dedicated time to work on code and ask questions. Some questions in progress tests will be from material covered in the labs Indicative ‘solutions’ for labs also provided in moodle Attendance at labs is compulsory! (and acted on in LEAP) Listen again I will use zoom recordings instead, and link to these on moodle. Will provide code snippets etc used in lectures on moodle Slide 9/69 Previously in CE303… Course follows same structure as last year. Both choice of material and assessments Lectures and labs should be enough to complete exercises/assignments. No specific textbook, but list of useful (optional) resources on moodle for your enjoyment. Self-directed learning encouraged! Past student feedback in recent years has been mostly positive “Negative feedback/comments in the past were highly correlated with students who attempted this course without a good background in java programming skills, who then struggled to keep up with the nature of the material” Slide 10/69 Part 1 Java basics revisited Java is an object-oriented language Unlike other languages, there are no ‘free’ functions in java. Everything works via Classes and Objects which expose methods. Even the ‘main’ entry point of programs meant to be executed by a shell. Classes can be organised into packages These act as namespaces for classes. Java Runtime Environment generally consists of JVM Utilities (e.g. java executable) (vs javac/javap in the JDK) Standard classes (including all implicitly imported ones from java.lang package) Slide 12/N The Java Virtual Machine The ClassLoader. What is in a compiled.class file? Metadata regarding package, number and names of methods, implemented interfaces, referenced classes, etc Method definitions (in bytecode) and class-specific constants See https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html if interested! The JVM Memory model Class (Method) Area Heap Stack (Program Counter Register) (Native method stacks) Slide 13/N The Four Pillars of Object-Oriented Programming Inheritance Encapsulation Abstraction Polymorphism Slide 14/N Inheritance Inheritance Typically described as an ‘is a’ relationship E.g. a Dog “is an” Animal Can lead to confusion, as other things can also be said to have an ‘is a’ relationship (e.g. Interfaces) Alternatively described as a “Parent / Child” relationship Useful when visualising hierarchy, but also misleading Better: Ability for one class to extend the functionality of another e.g. from simpler/general to ‘more elaborate’/specialised. But. Keep in mind SOLID principles of good Object-Oriented Design. This relationship is typically represented via UML diagrams Slide 16/N Inheritance - basics A class can extend another class We say that the subclass “inherits” from the super (“parent”) class A subclass inherits attributes and methods from its parent A subclass might end up ‘hiding’ parent attributes Typically should be avoided, as it leeds to confusing situations. A subclass can override parent methods In Java, a class extends at most one other class. i.e. single-rooted hierarchy, no multiple inheritance. Every class inherits from java.lang.Object Slide 17/N Inheritance – Overriding Methods To override means to replace the definition of a superclass method with another. Not to be confused with “overloading” The overriding method should have the same parameter signature (i.e. number and type of input parameters), and return either the same type, or a covariant return type to the original. Any method of the superclass can be overridden, unless declared final The overriding method has to be “at least as visible” as the original method. E.g. you can not override a public method to make it protected, default, or private. Slide 18/N // in file Employee.java public class Employee { protected String name; protected double salary; public Employee( String aName, double aSalary ) { name = aName; salary = aSalary; } public void setSalary( double aSalary ) { salary = aSalary; } public String getName () { return name; } public double getSalary() { return salary; } } // in file Manager.java public class Manager extends Employee { public double bonus; public Manager( String aName, double aSalary, double aBonus) { super( aName, aSalary ); bonus = aBonus; } void setBonus( double aBonus ) { bonus = aBonus; } public double getSalary() { return salary + bonus; } } Slide 19/N Covariant return type example An overriding method in a subclass may return a more specialised “variant” of the method being overridden. // in file Employee.java // in file Manager.java public class Employee { public class Manager extends Employee { … … public Employee copy(){ public Manager copy(){ return new Employee(name, salary); return new Manager(name, salary, bonus); } } } } Slide 20/N Inheritance – Invoking superclass methods and constructors A class can not access private features of its super class Superclass methods: If a subclass overrides a parent method, use the super keyword (as an object) to call the parent method inside the subclass There is no super.super (it would bypass the parent class) Slide 21/N Inheritance – Invoking superclass methods and constructors Superclass constructors: Use the super() call with appropriate arguments as the first statement in a constructor, to initialize the inherited superclass. If no explicit call to super(), assume implicit call to a parent constructor that takes no parameters This may also be an implicit / default constructor, as long as no other explicit constructors exist in the superclass. Superclass construction happens before initialization and execution of the rest of the subclass constructor body Important, e.g. in the case of instance initializers (standalone blocks that are run before the constructor statements, but after superclass initialization) Slide 22/N toString() method Returns a string representation Method is used silently in string concatenation. E.g. aString + anObject means aString + anObject.toString() Object.toString() consists of ClassName + the object’s HashCode System.out.print( obj ) calls obj.toString() implicitly. Slide 23/N public class Employee { … public String toString() { return getClass().getName() + "[name=" + name + ", salary=" + salary + "]"; } } public class Manager extends Employee { … public String toString() { return super.toString() + "[bonus=" + bonus + "]"; } } Slide 24/N Encapsulation Access modifiers Java provides 4 access modifiers. In order of visibility, from ‘least’ to ‘most’, they are: private, (default), protected, and public Private fields and methods cannot be accessed by any class or subclass Default fields and methods are “package private”: they are visible from other classes or subclasses within the package, but not outside of it. Protected: Visible by all classes or subclasses within the same package, or subclasses (but not other classes) from any external package. Public: Accessible from any class or package Classes and interfaces at the ‘top level’ of a file can only be public or (default). Slide 26/N Why are access modifiers useful? Why is it important to have such access levels? Why not make everything public? The reason, is “other people”, especially when working in large projects/teams. “Other people” could also be you in two months time, after you’ve forgotten what your code was supposed to do, and then you start breaking things! Encapsulation helps ‘protect’ classes from being used inappropriately and then ‘breaking’ because their internals were modified! By restricting access to precious internals and only providing a public interface for their use, you have a better reassurance that your class will work as intended! Slide 27/N Non-access modifiers There are other modifiers, which do not relate to access in terms of ‘visibility’: Final: In front of a class: the class cannot be extended / subclassed further. In front of a field: Can only be explicitly initialized once, and cannot be reassigned to further after that. In front of a method: The method is not allowed to be overridden in a subclass. Static (next slide) Abstract (next section) Synchronized / transient / volatile (next few lectures) Conventional order: [access modifier] [non-access modifier] [type] [name] Slide 28/N Static The static keyword means that the member is shared by all instances of the class. E.g. field x can be accessed from any instance of A or via the classname A itself (i.e. as A.x): public class A { private static int x = 0; … } One cannot access this or any non-static members from a static method. - If you find yourself tempted to change members to static to avoid compilation errors, you should probably reconsider your design instead! Slide 29/N Hiding vs Shadowing One aspect of encapsulation is ‘hiding’ or ‘shadowing’ of methods or variables, resulting in reduced visibility of the variables or methods that get affected. The two are similar but different concepts. Hiding typically refers to obscuring access to variables or static methods from a subclass. Shadowing typically refers to obscuring access of ‘outer’ scopes from ‘inner’ scopes. Slide 30/N Hiding An attribute in a subclass hides an attribute with the same name in a parent class (even if attribute has different type) The parent class attribute can still be accessed via the super keyword A static method in a subclass “hides” a static method with the same name in a parent class. Can still call the “hidden” method by prefixing the method name with the class name. Slide 31/N public class Main { public static void main( String [] args ) { Output: One.say(); Two.say(); Helloooooooo! Two.sayFromOne(); Also hellooo! } Helloooooooo! } class One { public static void say() { System.out.println( "Helloooooooo!" ); } } class Two extends One { public static void say() { System.out.println( "Also hellooo!" ); } public static void sayFromOne() { One.say(); } } Slide 32/N Shadowing If a variable in a particular (inner) scope has the same name as another declaration in an ‘enclosing’ (outer) scope, then the declaration shadows the declaration of the enclosing scope. You cannot refer to a shadowed declaration by its name alone, since this would be ambiguous; therefore to access the shadowed field, this needs to be qualified by the enclosing class's name as well as the this keyword. Slide 33/N public class ShadowTest { public int x = 0; class FirstLevel { public int x = 1; Output: void methodInFirstLevel(int x) { x = 23 System.out.println("x = " + x); this.x = 1 System.out.println("this.x = " + this.x); ShadowTest.this.x = 0 System.out.println( "ShadowTest.this.x = " + ShadowTest.this.x); } } public static void main(String... args) { ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); } } Slide 34/N Abstraction Abstraction in Java Two main types: Interfaces Abstract Classes Slide 36/N Interfaces An interface is a special reference type, similar to a class (but it is not a class, and cannot be instantiated itself!) An interface can be implemented by a class (often called “the implementor”) An interface dictates what functionality (i.e. public methods) must be present in a class, in order to be considered an implementation of that interface. Occasionally referred to as a ‘contract’ between the class and the interface A class can implement more than one interface(s) The intent is to “decouple the ‘interface’ (i.e. functionality) from the ‘implementation’ specifics” A user does not need to know how the steering wheel connects to the engine. They just need to know there’s a steering wheel! If you changed the engine type, the user shouldn’t have to change how they use the wheel! Slide 37/N Interfaces Interfaces can extend other interfaces. Multiple inheritance among interfaces is allowed (but, see “I” in “SOLID”) All methods defined in an interface are implicitly public and abstract i.e. they lack an implementation, and need to be publicly overridden – this is the whole point of an interface. All variables are implicitly static and final (i.e. constants). Special methods in interfaces Default methods (new from Java 8 onwards) Static methods (new from Java 8 onwards) Private / Private Static methods (accessible from default and static methods respectively, Java 9 onwards) Slide 38/N Slide 39/N Slide 40/N “for each” loops for (T x : myList) is shorthand for Iterator it = myList.iterator(); while ( it.hasNext() ) { T x = it.next(); } Leads to shorter, more readable code. Can be used with arrays, or any class implementing the Iterable interface Slide 41/N Default methods in Interfaces Introduced in Java 8. A default method is not abstract – has an implementation, right in the interface Default methods can, but do not have to be implemented by implementing classes. Useful when ‘evolving’ an interface (indeed Java itself has used this) Slide 42/N Default methods and the “multiple inheritance problem” If a class inherits several implementations of a method with the same name (either from default implementations only, or also with direct inheritance), we could have multiple inheritance conflicts. Java resolves these as follows: - Inheritance from a class has priority over inheritance from an interface - Derived interfaces or sub-interfaces take higher precedence than interfaces higher up in the inheritance hierarchy - If you code a new class that implements different interfaces which share the same method, and it is declared as default in at least one of them, then the method has to be explicitly overridden in the new class. Slide 43/N Slide 44/N Static methods in interfaces Introduced in Java 8 Similar to default methods But since they are static, we cannot override them in the implementation classes Having static methods in interfaces does not create a multiple inheritance problem Why? Because we don’t have to override them in the implementation classes, as we have to do with default methods Slide 45/N Abstract Classes and Methods A class or method is called ‘abstract’ if it is “incomplete” in some manner. An abstract method is a method that lacks a definition. If a class contains abstract methods, it must be labelled abstract. But can be labelled abstract even if no abstract methods are present An abstract class can therefore not be instantiated in itself, only extended. The extending class must somehow make all abstract things ‘concrete’, otherwise it is also abstract (since it is still incomplete!) Slide 46/N Why Abstract Classes and Methods? Abstract classes serve a different function than interfaces Although in other languages, e.g. C++, abstract classes are the way to create interfaces Think of it as a way of using a ‘template’ / injecting code that lots of classes might use, to save time / make your implementations more robust and less redundant; think of ‘extending’ an abstract class as a way of ‘dumping’ its contents (in a structured manner) into a child class, which aims to ‘fill in the gaps’. Good for the “Don’t Repeat Yourself” (DRY) principle. Slide 47/N Slide 48/N Slide 49/N Object composition as an alternative to inheritance Often, it is preferable to compose new classes from old classes by assigning objects as normal variables into the receipient class’s fields Instead of inheriting methods, the new class delegates requests directly to the objects assigned to its fields This is one way to “work around” the “no multiple inheritance” limitation of Java, since there is no limit to how many objects can be assigned to fields. Slide 50/N Slide 51/N Slide 52/N Polymorphism What is Polymorphism? The word means “many forms”. In other words objects (or their methods) can take many forms Two broad kinds: Compile-time polymorphism (method / operator overloading) Involves static binding (I.e. happens at compile-time) Unlike languages like C++, matlab/octave, or python, the only overloaded operator is “+” (numbers vs Strings) Runtime polymorphism (method overriding) Involves dynamic binding (i.e. happens at runtime) Slide 54/N Method Overloading Two or more methods in a class can have the same name, and represent entirely different methods! This is possible, as long as they have different parameter signatures. E.g.: They may have different number of input arguments The number of arguments is the same, but the types involved in the sequence of arguments is different Note, the return type does not participate in overloading; attempting to overload a method with the same parameter signature but different return types is not allowed Not to be confused with method overriding, which comes into play during inheritance, and where the signature in the extending class is identical! Slide 55/N Upcasting “Upcasting” is the act of “interpreting” a subclass as its parent type. - “Downcasting” generally not permitted (with some exceptions) One form of (runtime) polymorphism arises from implicit upcasting when passing arguments to methods. (we have already seen something similar with interfaces) public class Main { public static void main (String [] args) { Output: Base a = new Base(); Base b = new Subclass(); Subclass c = new Subclass(); sayHello(a); sayHello(b); sayHello(c); Hello from Base } Hello from Subclass Hello from Subclass public static void sayHello (Base x) { x.hello(); } } class Base { public void hello () { System.out.println("Hello from Base"); } } class Subclass extends Base { public void hello () { System.out.println("Hello from Subclass"); } } Slide 56/N Polymorphic Arrays A polymorphic array refers to the ability to create an array as type "Base class", but instantiate its elements via subclass constructors. This works via upcasting. class Base { public void hello() { System.out.println( "Hello from Base“ ); } } class Subclass1 extends Base { public void hello() { System.out.println( "Hello from Subclass1“ ); } } class Subclass2 extends Base { public void hello() { System.out.println( "Hello from Subclass2“ ); } } public class Main { public static void main (String [] args) { Base [] polymorphicArray = {new Base(), new Subclass1(), new Subclass2()}; for (Base x : polymorphicArray) { x.hello(); } Output: } } Hello from Base Hello from Subclass1 Hello from Subclass2 Slide 57/N Packages Not quite “polymorphism” as such, but one way in which classes of the same name can be distinguished from one another. Packages effectively act as namespaces. E.g. My.Awesome.Package.MyClass and com.ce303.MyClass are different classes. To declare that a particular class belongs to a particular package, the java code definition of the class’ file should start with an appropriate package declaration. E.g. to indicate that MyClass is part of the com.ce303 package, the first line in MyClass.java should be: package com.ce303; Packages in Java are created by placing the java definitions of your packaged classes in a folder hierarchy, which corresponds to the package’s name (or, name components, to be more exact)! E.g., if src is your ‘source root’ folder, then class com.ce303.MyClass should be in file src/com/ce303/MyClass.java From inside your ‘source root’ folder, assuming MyClass is your ‘main’ containing class, then: Type: javac./com/ce303/MyClass.java to compile MyClass.java (and, implicitly, all its dependencies as needed) Type: java com.ce303.MyClass to run the program (notice the use of ‘dots’ instead of ‘path separators’) Multiple ‘package-containing’ directories can be specified via the ‘classpath’ option, e.g.: javac -classpath “.:path1:path2” pkg1/Class1.java pkg2/Class2.java etc, then to run: java -classpath “.:path1:path2” pkg1.Class1 (assuming pkg1.Class1 contained a valid main function) Slide 58/N Functional Interfaces + Lambda Expressions and Method references Functional Interfaces A functional interface is any interface which only contains a Single Abstract Method. - A functional interface can contain more methods, as long as they’re not abstract (i.e. they have default implementations). - Note: Abstract methods that are direct descendants of the Object class are excluded from this definition. Unlike other languages (e.g. python) Java doesn’t treat “functions” (i.e. class methods) as legitimate objects that can be assigned or passed to other functions (i.e. “higher order” functions). Functional interfaces are Java’s mechanism for achieving this effect. Slide 60/N Example using a functional interface interface MyPredicate { boolean apply( int value ); } class SelectPositive implements MyPredicate { public boolean apply( int value ) { return value > 0; } } public class Main { public static void main( String [] args ) { int [] list = {1, 2, -2, -4, 5}; printSelected( list, new SelectPositive() ); } public static void printSelected( int [] array, MyPredicate predicate ) { for (int element : array) { if (predicate.apply( element )) { System.out.print( element + “ “ ); } } } } Slide 61/N Functional interfaces in the Java libraries The java.util.function package (in the java.base module) defines a variety of functional interfaces, e.g.: Function BiFunction Predicate UnaryOperator BinaryOperator Consumer Supplier And many specialisations for primitive types, e.g. IntToDoubleFunction ToDoubleBiFunction DoublePredicate IntBinaryOperator LongConsumer… Is there a more concise way of using all these functional interfaces than having to create class explicit implementations for each of these? Slide 62/N Anonymous Classes It is possible to implement an interface (any interface, not just functional ones) “on the spot”, instead of explicitly creating a class that implements it. - Note: In fact it is possible to extend existing classes anonymously “on the spot” in the same way. - Note: anonymous classes cannot have explicit constructors - Note: an anonymous class is a normal expression, which can be part of a normal statement; the statement needs to be terminated with a semicolon like all statements. Forgetting the semicolon after the closing brace of the definition of the anonymous class is a common mistake! - See the java specification for details (https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.9.5) E.g.: MyPredicate m = new MyPredicate () { boolean apply (int x) {return x>0;} }; Slide 63/N Lambda Expressions A lambda expression is a concise syntax, which, similar to anonymous classes, it represents an “on the spot” implementation of a functional interface (specifically). Lambda Expressions consist of: - Parameters to be supplied to the interface “function” (i.e. the target method) enclosed in parentheses - The arrow token: -> - A body, consisting of a block of statements, representing the “function’s” body. Notes: - The parameter types can be omitted, e.g. (a, b) -> { return a + b; } instead of (int a, int b) -> { return a+b; } - If only a single argument is used, parentheses can be omitted, e.g. x -> { return x + 1;} - If the lambda doesn’t take input arguments, an empty pair of brackets is used () -> { return 5; } - If the lambda block consists of a single return statement returning an expression, the block can be replaced by the expression itself, e.g. x -> { return x + 1; } becomes x -> x + 1 Slide 64/N Lambda Type Inference As long as a lambda can be matched to an appropriate functional interface, the parameter and return value types do not have to be explicitly defined. E.g. one can write: (a,b) -> a.toString() + b.toString() instead of (Person a, Person b) -> a.toString() + b.toString() as long as a) there is a valid functional interface to match against, e.g.: public interface PersonStringAdder { public String addPersonStrings (Person a, Person b); } and b) it’s the interface you’re attempting to match to in the specific context, e.g.: PersonStringAdder mypersonstring = (a,b) -> a.toString() + b.toString() Slide 65/N Lambda Expressions: Remark Java lambda expressions always need to be matched to a functional interface. E.g. IntBinaryOperator f = (a, b) -> a – b; You cannot assign a lambda expression to an Object variable: Object obj = (a, b) -> a – b // does NOT compile Slide 66/N Method references Very often, a lambda simply serves as a ‘redirector’, in that its role is simply to take some input arguments, and pass them straight into an existing method and return the result. E.g. (x) -> obj.method(x) Java provides a concise way to express such ‘redirector lambdas’ using “method references”. There are 4 types: Reference to a Type’s static method: (args) -> C.sm(args) is C::sm Reference to an object’s instance method: (args) -> o.im(args) is o::im Ref. to instance method of object of a certain type, passed as the first parameter to the lambda: (C o, args) -> o.im(args) is C::im Reference to a constructor: (args) -> new C(args) is C::new (Legend: sm denotes a static method, im denotes an instance method, o an instance object, C a classname) Slide 67/N Summary We have reviewed the basics of the Java Language We made particular reference to the four pillars of Object-Oriented Programming: Inheritance Encapsulation Abstraction Polymorphism We introduced: Functional Interfaces Anonymous Classes Lambdas Method References (in this unit, we will also talk about unit tests in the labs) Thank you for your attention! Next week on CE303: Module Supervisor: Unit 2 (21st Oct 2024) Dr Tasos Papastylianou ([email protected]) Threads and Synchronisation Academic Office Hours: Tuesdays, 10:00-12:00