Lambdas and streams
Introduction
Introduction to session by speaker before transitioning to Anna.
Quick inquiries regarding the students' progress on the assignment.
Introduction: Anna, former tutor, currently a software engineer at Google.
Anna's Background
Anna works in Payments Compliance Identity Verification at Google.
Importance explained: validating significant monetary transactions (e.g., ).
Examples given: selling on the Play Store, YouTube monetization.
Regulatory complexity illustrated by cross-border transactions (e.g., Australia to the US, EU regulations).
Personal background and academic qualifications:
Bachelor of Science majoring in Computer Science and Accounting.
Tutored multiple computer science courses (e.g., 1001, 2002).
Completed internships in Brisbane before joining Google.
Structure of the Lecture
Lecture focuses on:
Functional interfaces
Anonymous classes
Lambdas
Streams
Importance of understanding functional interfaces to grasp subsequent concepts clearly.
Coding Example: The Red Room Class
Problem statement: Create a class called Red Room that allows only patrons of drinking age.
Breakdown of tasks identified:
Create a method called enter that receives a list of patrons.
Patrons Class:
Contains properties like name and age.
Breath alcohol test check included.
Defining the Enter Method
Declaration of the enter method:
public void enter(List<Patron> prospectivePatrons) {
Age Check Logic:
Iterate through the list of patrons and check if age .
Occupants tracking through use of a Set (to avoid duplicates).
if (patron.getAge() >= 18) {
occupants.add(patron);
}
Testing Enter Method:
Create instances of patrons and test if the method properly allows entries based on age constraints.
Problem Identification and Solution
Acknowledgement that the age checking logic is hard-coded.
Discusses potential complexities like different regulations on different days (if patrons could be let in if accompanied).
Introduces the need to refactor by implementing the Bouncer interface.
Dependency Injection introduced to avoid hard-coding logic directly within the method.
public void enter(List<Patron> prospectivePatrons, Bouncer bouncer) {
Bouncer Interface:
Declares behavior through a method checkEntry(Patron p) to provide the logic for accepting patrons.
Implementation of Age Bouncer:
Create a class that implements Bouncer and defines the logic for checking age.
Conclusion on Refactoring Logic
Anonymous Classes:
Explanation given for use cases of anonymous classes. Define, instantiate, and use them in one go without naming.
Coding example: transforming the logic into an anonymous class for ease of implementation.
```java
Bouncer bouncer = new Bouncer() {
public boolean checkEntry(Patron p) {
return p.getAge() >= 18;
}
};```
- **Lambdas**:
- Introduced as a streamlined way of defining functionality for functional interfaces with syntax reduction.
- Refactor Age Bouncer implementation to use lambda expressions instead of anonymous classes:
Predicate<Patron> ageBouncer = (p) -> p.getAge() >= 18;
Discussed preference for lambdas over anonymous classes for clearer syntax.
Functional Interfaces and Their Power
Definition: a functional interface contains a single abstract method.
Various examples of common functional interfaces:
Function: takes one argument and returns a result.
Function<String, Integer> stringLength = s -> s.length(); System.out.println(stringLength.apply("hello")); // Output: 5Predicate: takes one argument and returns a boolean.
Predicate<Integer> isEven = n -> n % 2 == 0; System.out.println(isEven.test(4)); // Output: trueConsumer: takes one argument and returns nothing.
Consumer<String> greeter = s -> System.out.println("Hello, " + s); greeter.accept("World"); // Output: Hello, WorldSupplier: takes no arguments and returns a result.
Supplier<Double> randomValue = () -> Math.random(); System.out.println(randomValue.get()); // Output: a random double valuePreference to use standard functional interfaces over creating custom ones, enhancing code reusability and clarity.
Streams
Transition from discussing Lambdas to Streams.
Explanation of streams in the context of Java:
Streams allow performing aggregate operations over sequences of elements (like collections, arrays).
Demonstration on counting items in a list versus using streaming:
Manipulating the list directly through looping.
Using
stream(),filter(),map(), and other methods to perform operations declaratively.
Streams are lazy: operations are not executed until a terminal operation is invoked.
Stream Operations
Intermediary vs Terminal Operations:
Intermediaries (like filter, map) return a new stream.
Terminals (like collect, forEach) consume the stream.
Performance consideration: Filter as early as possible in the stream to reduce dataset size before processing heavy operations.
Collectors and Statistics
Discussed methods like
Collectors.toList()for gathering elements back into a list, ensuring that the original data source remains unchanged.Returning collections instead of streams where applicable is best practice.
More functions and variations: reduce, distinct, etc., that can be implemented on streams.
Infinite Streams
Example given on generating infinite streams using
Stream.iterate().Explanation on practical implementation to approximate Pi with a specified formula.
Input and Output in Java
Introduction to file handling and reading contents.
Importance of good practices in error handling while reading files, maintaining state clarity.
Recommendation against Java serialization due to security flaws; promoting the use of JSON or XML formats for data representation.
Brief instructions on implementing
BufferedReader, error handling and formatting for reading files.Importance of readability and useful error messaging when parsing file content.
Conclusion
Validated understanding of functional programming principles in Java through applied examples.
Encouraged the integration of advanced concepts like streams and lambdas in assignments to enhance programming skills.