
Explore generics and the collection framework in Java, covering Tree Set, Hash Maps, and Optional to avoid null pointer exceptions, then dive into Java streams for concise, powerful operations.
Understand lambda expressions, references, and method references to prepare. Apply var's type inference from Java 10 and follow along with Java 11; Java 8 remains workable with explicit types.
Explain how the object class is the parent of all classes and how a store can hold any object, including autoboxed values, highlighting the role of generics in type safety.
convert a class into a generic class by introducing a type parameter t, replacing object with t in fields and methods, and creating type-safe instances that reflect the chosen type.
Explore naming conventions for generics by using a single uppercase letter for type parameters, with examples like E for element, V for value, and C for generic data.
Explore a generic class with multiple type parameters, using value one and value two of types U and V. Learn how different type combinations affect set and get operations.
Explore bounded types in generics by using extends to bound type parameters, allowing a store to accept only types that extend number or a user-defined class.
Explore bounded types for interfaces by defining a car interface and a Ferrari class that implements it, then bound a generic store to accept only cars.
Explore generics with a generic store class using a type parameter t, implement a list-length comparison method, and apply wild cards to accept stores of any type.
Explore bounded wildcards in Java generics by using extends to limit a wildcard to number types and their subclasses, ensuring methods accept only numeric stores while preserving flexibility.
Learn about lower bound wildcards in Java generics, using super to accept a type or its supertypes, and why extends restricts to subtypes in method parameters.
Learn how to implement a generic method in a non generic class using a type parameter T, with type inference simplifying calls and optional bounds with extends no.
Declare a generic constructor with type parameter T on a store class to control what can be passed when creating objects. The lecture shows constraining inputs to enforce valid types.
Explore generic interfaces that define get and set methods for positions, implement them with a concrete type, or keep the interface generic to support any type.
Discover raw types in Java generics, showing how non generic usage mirrors old code, the need for casting, and how specifying the type parameter enforces safety.
Explore how a generic superclass can be extended by a subclass, with explicit type arguments, and how the generic type flows from store to box using integers or strings.
Explore how a generic subclass extends a generic box, showing that the superclass must be generic and that inherited box methods like open remain accessible.
Discover the Java collection framework, including core interfaces such as collection, list, set, queue, and map, and learn how iterators traverse collections, and sets enforce uniqueness.
This lecture explains that interfaces cannot be instantiated, so collection classes implement them; some are abstract, others implement features, with list implementations and generics using reference types rather than primitives.
Explore how generics work in Java by creating a typed array list that holds integers, showing autoboxing, dynamic size, index access, and printing all elements.
Learn how ArrayList add and remove methods manage elements, including auto-generated indices, inserting at specific positions, and removing by index or by object, with examples.
This lecture demonstrates using ArrayList.set to update a value at a specific index, and using addAll to merge another list and removeAll to delete elements.
Explore ArrayList removeIf with a predicate and lambda, clear a list, and use contains to check for elements in Java collections.
Use the Arrays class to initialize lists in one step, and recognize that such lists are immutable and reject additions; create mutable lists by passing elements into a constructor.
Navigate lists with iterators by using next and hasNext, and move backward with hasPrevious. Learn to set even elements to zero and compare with the for-each loop.
The lecture explains spliterators, using forEachRemaining with a lambda to process elements, and tryAdvance in a while loop, noting parallelism benefits and tool selection.
Compare traditional for loops and for-each loops to iterate over a list, showing index-based traversal, element access, unboxing to int, and printing each value.
Explore using a list of reference type users in Java, adding user objects directly, retrieving with get, and printing with toString, highlighting generics and type safety in the collection framework.
Create a new list with List.of by listing the elements you want. Attempting to add elements throws an UnsupportedOperationException, highlighting its simple fast option when you won't modify the list.
Convert list to array and back by transforming a list into an array, then back to a list, and access elements by index using square brackets.
Explore the linked list as a class that implements the list interface, compare its behavior with an array list, and show queue and deque usage and indexed access.
Explore hash set, a fast set implementation that stores unique elements. Note that iteration does not guarantee insertion order, and duplicates are automatically ignored, illustrating when to use for speed.
Learn how HashSet capacity and load factor govern automatic resizing, starting from a default capacity of 16, with a 0.75 load factor that triggers doubling as elements fill up.
LinkedHashSet preserves insertion order like a list while offering hash set performance, so elements print in the order you insert them, unlike a standard hash set.
TreeSet keeps elements in ascending order as you insert them, offering automatic arrangement, unlike hash sets. When dealing with objects, use a comparator to define ordering in Java.
Explore the comparator interface, implement a custom comparison with an anonymous class, and pass it to a TreeSet to define the order of elements beyond the natural order.
Use a comparator to compare cars by price and store them in a tree set, implementing with an anonymous class or a lambda and overriding toString for readable output.
Explore the queue interface and its implementations, learn that queues follow first-in, first-out order, and see how classes like LinkedList implement both queue and list behaviors with subtle differences.
Explore the advanced features of Java linked lists in the collections framework, including generics, add and addFirst, peek for the first element, and deque-like head operations.
Discover how a LinkedList implements the List interface, allowing a List type reference to access LinkedList methods, add elements by index, and iterate to print values.
Explore how a linked list implements a first in, first out queue with add and offer, and how to peek, poll, remove, and remove(element), plus iterating with a for-each loop.
Explore how a linked list can function as a deque, supporting addFirst, addLast, removeFirst, removeLast, and getFirst and getLast operations from both ends.
Explore ArrayDeque, a double-ended queue that lets you add elements at the head or the last, and provides peak, remove first, remove last, and a descending iterator.
Discover how maps store values using a key-value structure, where a specific key retrieves its associated value. Compare maps to lists and learn that keys can be integers or strings.
Explore how a hash map implements the map interface by using put to store integer keys and values, and get to retrieve them, with unique keys and possibly shared values.
Understand how hash maps handle keys and values, and compare put versus putIfAbsent: put replaces an existing value, while putIfAbsent inserts only when the key is absent.
Explore how HashMap handles missing keys with getOrDefault, using get and a default value, and iterating over entry sets to access keys and values with for-each.
Learn how to access hash map values with values(), retrieve keys with keySet(), and remove entries using remove(key), which returns the removed value.
Explore hash map remove and replace operations: remove(key) deletes by key, remove(key, value) deletes only when the key has that value, and replace variants update values unconditionally or conditionally.
Apply hashmaps replaceAll to replace each value by a function of the key and value, using a lambda to generate new values such as value plus ten.
Explore how hash maps use compute, compute if absent, and compute if present to update values with key-based functions, including key times hundred and value plus hundred.
Explore how hash maps merge values with the merge method: if a key exists, apply a remapping function to old and new values; if not, insert the new value.
Learn HashMap extra methods for practical checks: use containsKey and containsValue to verify entries, check size and isEmpty, and clear the map to remove all elements.
TreeMap orders elements according to their keys, unlike hash map that doesn’t follow insertion order; with custom keys you must define how they are compared to arrange them.
Discover how LinkedHashMap preserves insertion order, ensuring the first element prints first and the last prints last, offering predictable iteration compared to a standard hash map.
Implement the comparable interface by defining compareTo for score-based ordering, use a lambda comparator for custom ordering, and observe a tree set sorting by score or by age.
Demonstrates how Optional helps manage absent values in Java to prevent null pointer exceptions when retrieving elements by index from a list.
Explore optional initialisation in Java by using Optional in return types, creating Optional.of and Optional.empty, and retrieving values with get while understanding generics and empty vs present.
Learn to safely use Optional by checking isPresent before calling get to avoid NoSuchElementException. Optional can be empty or contain a value; isEmpty notes emptiness, while Optional.ofNullable handles nulls.
Differentiate between optional of wrapper classes and optional of primitive; stream's average returns an OptionalDouble, a primitive double, not a wrapper.
Explore how to use optional.orElse, optional.orElseGet, and optional.orElseThrow to handle empty optionals, supply defaults with lambdas or method references, and customize exceptions.
Transform optional values with the map method by applying a lambda to convert integers to strings or other types, then retrieve results with get or orElse.
Explore how optional.filter uses a predicate and a lambda expression to keep only matching values, returning an empty optional when it fails and using orElse to supply a default.
Learn how Optional.ifPresent runs a consumer only when a value is present. Then compare Optional.ifPresentOrElse, which supplies a consumer when present and an empty action when absent.
Convert a non-null return to an Optional, use Optional.of and Optional.empty, and handle missing elements with or else and filter.
Explore how to use optional on nullable returns, convert a possibly null person to an optional, and employ ifPresent to avoid null pointer exceptions, with implications for the Streams API.
Create new streams from data stores, treat streams as sequences of objects, apply intermediate operations like filter, then run a terminal operation such as for each to print.
Create streams from existing collections by calling list.stream(). Use forEach or filter to process elements, with the original list remaining unchanged.
Learn how to create an IntStream from a primitive int[] array, understand boxing to Integer objects, and filter and print even elements using stream operations.
Create streams from primitive values in Java using IntStream, DoubleStream, and LongStream, including range generation. See how primitive streams avoid boxing and support filtering and printing.
Sort stream elements with the sorted method, using natural order or a comparator, then print them. Use min and max with optional results and method references to compare numbers.
Demonstrates how min and max operate directly on primitive int streams, unlike streams of Integer objects that require a comparator and optional handling for results.
Explore the Java Streams API's count method, counting elements after intermediate operations like filter, demonstrating how many elements meet criteria such as being even.
Demonstrate how the stream reduce method transforms a stream of elements into a single value, using an identity or optional result, with practical examples.
Call reduce on a list of person objects using a binary operator or comparator to find the max by age or min by score, returning an optional.
Learn how the map operation transforms a list into a new stream by adding 10 to every element, optionally filtering results, with direct call patterns and for-each usage.
Demonstrates converting streams of objects to primitive streams using mapToInt, mapToDouble, and mapToLong, then performing aggregate operations like max and sum on the resulting primitive streams.
Learn how to map a stream of primitive values to a stream of objects using map to object, with examples like adding a dollar sign to numbers and printing objects.
Understand the stream flatMap operation in Java: flatMap maps each element to multiple elements, enabling a one-to-many transformation and, when needed, flat maps to an int stream for primitive values.
Use stream methods anyMatch, allMatch, and noneMatch with predicates. Verify if any, all, or none of the elements satisfy a given condition in Java streams.
Learn to build streams incrementally with a stream builder by using accept to add elements from text files or user input, finalize with build, then apply map and sum operations.
Use the stream collect method to gather results into a container with a supplier, an accumulator, and a combiner, and collect even numbers into a list or set.
Learn to collect results with Collectors.toList and Collectors.toSet, demonstrated on a person class to filter by age and extract unique ages.
Map each person to their name using a stream, then collect with Collectors.joining to produce a delimited string, optionally with a prefix and suffix.
Learn how to use collectors to map a stream of objects into a map by choosing a key field, such as name or id, and a corresponding value field.
Discover how collectors.partitioningby splits input by a predicate such as scores greater than 50 into true and false partitions, producing map of lists and enabling access to first true element.
Explore Java generics and the Streams API by applying Collectors.partitioningBy, a two-argument operation with a predicate and a downstream collector, to count, summarize, or compute averages for partitions.
Use the groupingBy collector to organize a collection by a chosen key, producing a map of age to lists of people and retrieving age-specific groups.
Explore generics and the collections framework, learn two ways to create generic classes, and use the streams API to perform operations on collections and stay current with Java's features.
Learn about Java Generics and how to create Generic classes. You also learn about Generic Interfaces and Methods.
After learning and understanding Java Generics we then dive into the Java Collections Framework where we learn about data structures such as List, ArrayList, HashMap, HashSet, LinkedList... and so on. Generics are an important part of the Java programming language.
We have extra lessons on Java Optional which helps us avoid null pointer exceptions in Java. You will learn about Optionals because it's knowledge will be applied when you learn about Java Streams API.
Finally, we learn about the Streams API, how it works and the various methods such as filter(), map(), flatMap(), reduce(), collect() ... and so on.
After this course, you should have a solid understanding of the Java Generics, the Collection Framework with its Data Structures and the Java Streams API.
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types. (Java Docs)