14 The Stream API.

Slides:



Advertisements
Similar presentations
Lists and the Collection Interface Chapter 4. Chapter Objectives To become familiar with the List interface To understand how to write an array-based.
Advertisements

George Blank University Lecturer. CS 602 Java and the Web Object Oriented Software Development Using Java Chapter 4.
Lists and the Collection Interface Chapter 4. Chapter 4: Lists and the Collection Interface2 Chapter Objectives To become familiar with the List interface.
Fall 2007CS 2251 Lists and the Collection Interface Chapter 4.
©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 10 *Arrays with more than one dimension *Java Collections API.
Slides prepared by Rose Williams, Binghamton University Chapter 16 Collections and Iterators.
Chapter 10 2D Arrays Collection Classes. Topics Arrays with more than one dimension Java Collections API ArrayList Map.
Chapter 17 Java SE 8 Lambdas and Streams
Lambdas and Streams. Functional interfaces Functional interfaces are also known as single abstract method (SAM) interfaces. Package java.util.function.
GENERIC COLLECTIONS. Type-Wrapper Classes  Each primitive type has a corresponding type- wrapper class (in package java.lang).  These classes are called.
5-Aug-2002cse Arrays © 2002 University of Washington1 Arrays CSE 142, Summer 2002 Computer Programming 1
1 © 2002, Cisco Systems, Inc. All rights reserved. Arrays Chapter 7.
Inheritance. Inheritance - Introduction Idea behind is to create new classes that are built on existing classes – you reuse the methods and fields and.
Java8 Released: March 18, Lambda Expressions.
1 CSC 2053 New from AutoBoxing 3 Before J2SE 5.0, working with primitive types required the repetitive work of converting between the primitive.
Arrays Chapter 6. Objectives learn about arrays and how to use them in Java programs learn how to use array parameters and how to define methods that.
Slides prepared by Rose Williams, Binghamton University Chapter 16 Collections and Iterators.
CMSC 202 Containers and Iterators. Container Definition A “container” is a data structure whose purpose is to hold objects. Most languages support several.
Lambdas and Streams. Stream manipulation Class Employee represents an employee with a first name, last name, salary and department and provides methods.
Chapter 9 Introduction to Arrays Fundamentals of Java.
Functional Processing of Collections (Advanced) 6.0.
9.1 CLASS (STATIC) VARIABLES AND METHODS Defining classes is only one aspect of object-oriented programming. The real power of object-oriented programming.
Lists and the Collection Interface Chapter 4. Chapter 4: Lists and the Collection Interface2 Chapter Objectives To become familiar with the List interface.
Arrays Chapter 7.
Lambdas & Streams Laboratory
CMSC 202 ArrayList Aug 9, 2007.
Modern Programming Tools And Techniques-I
Topic: Classes and Objects
Sixth Lecture ArrayList Abstract Class and Interface
EECE 310: Software Engineering
Introduction to LINQ and Generic Collections
Functional Programming and Stream API
Taking Java from purely OOP by adding “functional level Programming”
Java Primer 1: Types, Classes and Operators
GC211Data Structure Lecture2 Sara Alhajjam.
Chapter 20 Generic Classes and Methods
Functional Processing of Collections (Advanced)
Section 11.1 Class Variables and Methods
Java Review: Reference Types
Java Algorithms.
Primitive Types Vs. Reference Types, Strings, Enumerations
Functional Programming with Java
Topic 7 Interfaces I once attended a Java user group meeting where James Gosling (one of Java's creators) was the featured speaker. During the memorable.
.NET and .NET Core 5.2 Type Operations Pan Wuming 2016.
Constructor Overloading
Chapter 8: Collections: Arrays
Java How to Program, Late Objects Version, 10/e
CISC124 Assignment 4 on Inheritance due next Monday, the 12th at 7pm.
CISC124 Assignment 4 on Inheritance due next Monday, the 12th at 7pm.
COS 260 DAY 10 Tony Gauvin.
13 Lambda Expressions.
CHAPTER 6 GENERAL-PURPOSE METHODS
Object Oriented Programming in java
Arrays and Collections
Object Oriented Programming in java
Java – Inheritance.
A few of the more significant changes and additions. James Brucker
Containers and Iterators
Lambda Expressions.
CIS 199 Final Review.
Fundamental OOP Programming Structures in Java: Comments, Data Types, Variables, Assignments, Operators.
In this class, we will cover:
Classes, Objects and Methods
Winter 2019 CMPE212 5/3/2019 CMPE212 – Reminders
Chapter 19 Generics.
CMPE212 – Reminders Assignment 4 on Inheritance due next Friday.
„Lambda expressions, Optional”
A type is a collection of values
Chapter 7 Objects and Classes
Generics, Lambdas and Reflection
Presentation transcript:

14 The Stream API

Reference Book This chapter is based on Chapter 29 of Java the Complete Reference,9th Ed. (JCR-9e) by Herbert Schildt Oracle Press

Outline The Stream API Stream Basics

The Stream API Two of the most important new features added to JDK 8: lambda expressions the stream API the stream API is designed with lambda expressions in mind. provides some of the most significant demonstrations of the power that lambdas bring to Java

The Stream API (cont.) designed compatibile with lambda expressions the key aspect of the stream API: its ability to perform very sophisticated operations: search, filter, map, or manipulate data construct sequences of actions that resemble, SQL queries can be performed in parallel - a high level of efficiency large data sets - provides a powerful means of handling data in an efficient easy to use way.

The Stream API (cont.) an important point the stream API - advanced features requires a solid understanding: generics lambda expressions basic concepts of parallel execution a working knowledge of the Collections Framework

Outline Stream Basics Stream Interfaces How to Obtain a Stream A Simple Stream Example

Stream Basics the term stream - the stream API: a stream is a conduit for data represents a sequence of objects operates on a data source an array or a collection never provides storage for the data. It simply moves data- filtering, sorting, or operating on that data in the process a stream operation by itself does not modify the data source For example, sorting a stream does not change the order of the source results in the creation of a new stream that produces the sorted result

Stream Interfaces The stream API defines several stream interfaces, packaged - java.util.stream At the foundation – BaseStream defines the basic functionality available in all streams BaseStream - a generic interface declared like this: interface BaseStream<T, S extends BaseStream<T, S>> Here, T specifies the type of the elements in the stream S specifies the type of stream that extends BaseStream The methods declared by BaseStream are shown in Table 29-1 of JCR-9e

Stream Interfaces (cont.) From BaseStream several stream interfaces are derived The most general - Stream. It is declared as: interface Stream<T> Here, T specifies the type of the elements in the stream. Because it is generic, Stream is used for all reference types. In addition to the methods that it inherits from BaseStream, the Stream interface adds several of its own, a sampling of which is shown in Table 29-2.JCR-9e

A Sampling of Methods Declared by Stream <R, A> R collect(Collector<? super T, A, R> collectorFunc) Collects elements into a container, which is changeable, and returns the container. This is called a mutable reduction operation. Here, R specifies the type of the resulting container T specifies the element type of the invoking stream A specifies the internal accumulated type The collectorFunc specifies how the collection process works. (Terminal operation) long count( ) ounts the number of elements in the stream and returns the result. (Terminal operation)

A Sampling of Methods Declared by Stream (cont.) Stream<T> filter(Predicate<? super T> pred) Produces a stream that contains those elements from the invoking stream that satisfy the predicate specified by pred. (Intermediate operation) void forEach(Consumer<? super T> action) For each element in the invoking stream, the code specified by action is executed. (Terminal operation) <R> Stream<R> map(Function<? super T, ? extends R> mapFunc) Applies mapFunc to the elements from the invoking stream, yielding a new stream that contains those elements. (Intermediate operation.)

A Sampling of Methods Declared by Stream (cont.) DoubleStream mapToDouble(ToDoubleFunction<? super T> mapFunc) Applies mapFunc to the elements from the invoking stream, yielding a new DoubleStream that contains those elements. (Intermediate operation.) IntStream mapToInt(ToIntFunction<? super T> mapFunc) Applies mapFunc to the elements from the invoking stream, yielding a new IntStream that contains those elements. (Intermediate operation.) LongStream mapToLong(ToLongFunction<? super T> mapFunc) Applies mapFunc to the elements from the invoking stream, yielding a new LongStream that contains those elements (Intermediate operation)

A Sampling of Methods Declared by Stream (cont.) Optional<T> max(Comparator<? super T> comp) Using the ordering specified by comp, finds and returns the maximum element in the invoking stream (Terminal operation) Optional<T> min(Comparator<? super T> comp) Using the ordering specified by comp, finds and returns the minimum element in the invoking stream. (Terminal operation.)

A Sampling of Methods Declared by Stream (cont.) T reduce(T identityVal, BinaryOperator<T> accumulator) Returns a result based on the elements in the invoking stream. This is called a reduction operation. (Terminal operation.) Stream<T> sorted( ) Produces a new stream that contains the elements of the invoking stream sorted in natural order. (Intermediate operation.) Object[] toArray( ) Creates an array from the elements in the invoking stream. (Terminal operation.)

terminal and intermediate operations A terminal operation consumes the stream It produces a result, such as finding the minimum value in tstream, or to execute some action, as is the case with the forEach( ) method. Once a stream has been consumed, it cannot be reused. Intermediate operations produce another stream to create a pipeline that performs a sequence of actions. do not take place immediately the specified action is performed when a terminal operation is executed on the new stream created by an intermediate operation. This mechanism is referred to as lazy behavior, and the intermediate operations - lazy lazy behavior - stream API to perform more efficiently

stateless and stateful operations some intermediate operations are stateless and some are stateful In a stateless operation: each element is processed independently of the others In a stateful operation; the processing of an element may depend on aspects of the other elements

stateless and stateful operations -examples sorting - stateful operation an element’s order depends on the values of the other elements sorted( ) method is stateful. filtering elements based on a stateless predicate is stateless each element is handled individually filter( ) stateless

for primitive types Stream operates can’t operate directly on primitive types To handle primitive type stream - the stream API defines: DoubleStream IntStream LongStream all extend BaseStream and have capabilities similar to Stream

How to Obtain a Stream a stream is obtained for a collection JDK 8, the Collection interface methods obtain a stream from a collection - stream( ), default Stream<E> stream( ) Its default implementation returns a sequential stream The second method is parallelStream( )

How to Obtain a Stream (cont.) stream from an array - static stream( ) method of the Arrays class static <T> Stream<T> stream(T[ ] array) returns a sequential stream to the elements in array. For example, given an array called addresses of type Address, the following obtains a stream to it: Stream<Address> addrStrm = Arrays.stream(addresses);

A Simple Stream Example an example that uses streams the following program creates an ArrayList called myList that holds a collection of integers next, obtains a stream that uses myList as a source then demonstrates various stream operations

class StreamDemo // Demonstrate several stream operations. import java.util.*; import java.util.stream.*; class StreamDemo { public static void main(String[] args) { // Create a list of Integer values. ArrayList<Integer> myList = new ArrayList<>( ); myList.add(7); myList.add(18); myList.add(10); myList.add(24); myList.add(17); myList.add(5); System.out.println("Original list: " + myList);

class StreamDemo (cont.) // Obtain a Stream to the array list. Stream<Integer> myStream = myList.stream(); // Obtain the minimum and maximum value // by use of min(), max(), isPresent(), and get(). Optional<Integer> minVal = myStream.min(Integer::compare); if(minVal.isPresent()) System.out.println("Minimum value: " + minVal.get());

class StreamDemo (cont.) // Must obtain a new stream // because previous call to min() // is a terminal operation // that consumed the stream. myStream = myList.stream(); Optional<Integer> maxVal = myStream.max(Integer::compare); if(maxVal.isPresent()) System.out.println("Maximum value: " + maxVal.get());

class StreamDemo (cont.) // Sort the stream by use of sorted(). Stream<Integer> sortedStream = myList.stream().sorted(); // Display the sorted stream by use of forEach(). System.out.print("Sorted stream: "); sortedStream.forEach((n) -> System.out.print(n + " ")); System.out.println();

class StreamDemo (cont.) // Display only the odd values by use of filter(). Stream<Integer> oddVals = myList.stream().sorted().filter((n) -> (n % 2) == 1); System.out.print("Odd values: "); oddVals.forEach((n) -> System.out.print(n + " ")); System.out.println();

class StreamDemo (cont.) // Display only the odd values // that are greater than 5. // Notice that two filter operations are pipelined. oddVals = myList.stream().filter( (n) -> (n % 2) == 1) .filter((n) -> n > 5); System.out.print("Odd values greater than 5: "); oddVals.forEach((n) -> System.out.print(n + " ") ); System.out.println(); }

Output Original list: [7, 18, 10, 24, 17, 5] Minimum value: 5 Maximum value: 24 Sorted stream: 5 7 10 17 18 24 Odd values: 5 7 17 Odd values greater than 5: 7 17

Explanations After creating an ArrayList, the program obtains a stream for the list by calling stream( ): Stream<Integer> myStream = myList.stream(); the Collection interface defines the stream( ) method obtains a stream from the invoking collection as Collection is implemented by every collection class stream( ) can be used to obtain stream for any type of collection, including the ArrayList a reference to the stream is assigned to myStream

obtaining mimimum value in the stream the program obtains the minimum value in the stream also the minimum value in the data source and displays it: Optional<Integer> minVal = myStream.min(Integer::compare); if(minVal.isPresent()) System.out.println("Minimum value: " + minVal.get()); from Table 29-2 - min( ) is declared like this: Optional<T> min(Comparator<? super T> comp)

min’s parameter - Comperator notice that the type of min( )’s parameter is a Comparator is used to compare two elements in the stream min( ) is passed a method reference to Integer’s compare( ) method is used to implement a Comparator capable of comparing two Integers.

return typeof min - Optimal the return type of min( ) is Optional Optional is a generic class packaged in java.util, declared as: class Optional<T> Here, T specifies the element type An Optional instance can either contain a value of type T or be empty.

method isPresent and get use isPresent( ) to determine if a value is present Assuming that a value is available it can be obtained by calling get( ) here, the object returned will hold the minimum value of the stream as an Integer object.

min() is a terminal operation an important point min( ) is a terminal operation that consumes the stream myStream cannot be used again after min( ) executes

obtaining maximum of the stream The next lines obtain and display the maximum value in the stream: myStream = myList.stream(); Optional<Integer> maxVal = myStream.max(Integer::compare); if(maxVal.isPresent()) System.out.println("Maximum value: " + maxVal.get());

obtaining maximum of the stream (cont.) First, myStream is once again assigned the stream returned by myList.stream( ) this is necessary: the previous call to min( ) consumed the previous stream Next, the max( ) method is called to obtain the maximum value Like min( ), max( ) returns an Optional object. Its value is obtained by calling get( )

method sorted The program then obtains a sorted stream through the use of this line: Stream<Integer> sortedStream = myList.stream().sorted(); Here, the sorted( ) method is called on the stream returned by myList.stream( ) sorted( ) is an intermediate operation its result is a new stream this is the stream assigned to sortedStream

method forEach The contents of the sorted stream are displayed by use of forEach( ): sortedStream.forEach((n) -> System.out.print(n + " ")); Here, the forEach( ) method executes an operation on each element in the stream. In this case, it simply calls System.out.print( ) for each element in sortedStream. by use of a lambda expression.

method forEach (cont.) The forEach( ) method has this general form: void forEach(Consumer<? super T> action) Consumer is a generic functional interface declared in java.util.function Its abstract method is accept( ): void accept(T objRef) The lambda expression in the call to forEach( ) provides the implementation of accept( ). The forEach( ) method is a terminal operation after it completes the stream has been consumed

method filter Next, a sorted stream is filtered by filter( ) so that it contains only odd values: Stream<Integer> oddVals = myList.stream().sorted().filter((n) -> (n % 2) == 1); The filter( ) method filters a stream based on a predicate It returns a new stream that contains only those elements that satisfy the predicate: Stream<T> filter(Predicate<? super T> pred)

interface Predicate Predicate - a generic functional interface defined in java.util.function Its abstract method - test( ): boolean test(T objRef) It returns true if the object referred to by objRef satisfies the predicate and false otherwise.

filter method’s parameter The lambda expression passed to filter( ) implements this method. filter( ) is an intermediate operation it returns a new stream that contains filtered values here are the odd numbers These elements are then displayed via forEach( ) as before.

sequential filtering Because filter( ), or any other intermediate operation, returns a new stream it is possible to filter a filtered stream a second time. as show in the following line: a stream that contains only those odd values greater than 5: oddVals = myList.stream().filter((n) -> (n % 2) == 1) .filter((n) -> n > 5); Notice that lambda expressions are passed to both filters

Reduction Operations min( ) and max( ) methods - terminal operations return a result based on the elements in the stream In the language of the stream API - reduction operations each reduces a stream to a single value the minimum and maximum. The stream API refers special case reductions a specific function other special case reductions: such as count( ) counts the number of elements in a stream

Reduction Operations (cont.) the stream API generalizes reduce( ) method return a value from a stream based on any arbitrary criteria all reduction operations - terminal operations

Reduction Operations (cont.) Stream defines three versions of reduce( ) two are: Optional<T> reduce(BinaryOperator<T> accumulator) T reduce(T identityVal, BinaryOperator<T> accumulator) the first returns an object of type Optional, the second returns an object of type T - element type of the stream accumulator - a function that operates on two values and produces a result identityVal - a value an accumulator operation involving identityVal and any element of the stream yields that element, unchanged.

Reduction Operations (cont.) E.g.: if the operation is addition the identity value will be 0 because 0 + x is x. For multiplication, the value will be 1, because 1 * x is x

Reduction Operations (cont.) BinaryOperator - functional interface declared in java.util.function specifies the mehtod apply( ) as follows: T apply(T val, T val2) as it relates to reduce( ): val will contain the previous result val2 will contain the next element In its first invocation val will contain either the identity value or the first element depending on which version of reduce( ) is used

Reduction Operations (cont.) the accumulator operation must satisfy three constraints. Stateless Non-interfering Associative stateless - the operation does not rely on any state information. each element is processed independently Non-interfering - the data source is not modified by the operation.

Reduction Operations (cont.) the operation must be associative. - arithmetic sense, E.g.: (10 * 2) * 7 the same result as 10 * (2 * 7) particular importance to the use of reduction operations on parallel streams,

Example The following program demonstrates the versions of reduce( ) just described

class StreamDemo2 // Demonstrate the reduce() method. import java.util.*; import java.util.stream.*; class StreamDemo2 { public static void main(String[] args) { // Create a list of Integer values. ArrayList<Integer> myList = new ArrayList<>( ); myList.add(7); myList.add(18); myList.add(10); myList.add(24); myList.add(17); myList.add(5);

class StreamDemo2 (cont.) // Two ways to obtain the integer product of the elements // in myList by use of reduce(). Optional<Integer> productObj = myList.stream().reduce((a,b) -> a*b); if(productObj.isPresent()) System.out.println("Product as Optional: " + productObj.get()); int product = myList.stream().reduce(1, (a,b) -> a*b); System.out.println("Product as int: " + product); }

Output Product as Optional: 2570400 Product as int: 2570400

Explanations first version of reduce( ) uses the lambda expression to produce a product of two values the stream contains Integer values Integer objects - unboxed for the multiplication and reboxed to return the result. The two values represent the current value of the running result and the next element in the stream The final result is returned in an object of type Optional. The value is obtained by calling get( ) on the returned object

Explanations (cont.) second version, the identity value is explicitly specified, for multiplication – 1 Notice that: the result is returned as an object of the element type Integer

Reduction Operations (cont.) simple reduction operations - multiplication are useful, the following obtains the product of only the even values: int evenProduct = myList.stream().reduce(1, (a,b) -> { if(b%2 == 0) return a*b; else return a;}); If b is even, then, a * b is returned otherwise, a is returned a holds the current result and b holds the next element,

Mapping it is useful to map the elements of one stream to another E.g.: a stream that contains a database of name, telephone, and e-mail address information might map only the name and e-mail address portions to another stream E.g.:apply some transformation to the elements in a stream map the transformed elements to a new stream.

Mapping (cont.) The most general mapping method is map( ) : <R> Stream<R> map(Function<? super T, ? extends R> mapFunc) Here R specifies the type of elements of the new stream T is the type of elements of the invoking stream mapFunc is an instance of Function -does the mapping. The map function must be stateless and non-interfering. a new stream is returned, map( ) is an intermediate method

Mapping (cont.) Function is a functional interface declared in java.util.function declared as: Function<T, R> As it relates to map( ) T is the element type R is the result of the mapping Function has the abstract method : R apply(T val) Here, val is a reference to the object being mapped. The mapped result is returned

Example a simple example of map() the program computes the product of the square roots of the values in an ArrayList In this version, the square roots of the elements are first mapped to a new stream Then, reduce( ) is employed to compute the product

class StreamDemo4 // Map one stream to another. import java.util.*; import java.util.stream.*; class StreamDemo4 { public static void main(String[] args) { // A list of double values. ArrayList<Double> myList = new ArrayList<>( ); myList.add(7.0); myList.add(18.0); myList.add(10.0); myList.add(24.0); myList.add(17.0); myList.add(5.0);

class StreamDemo4 (cont.) // Map the square root of the elements in myList to a new stream. Stream<Double> sqrtRootStrm = myList.stream().map((a) -> Math.sqrt(a)); // Find the product of the square roots. double productOfSqrRoots = sqrtRootStrm.reduce(1.0, (a,b) -> a*b); System.out.println("Product of square roots is " + productOfSqrRoots); }

Explanations the transformation (i.e., the computation of the square roots) occurs during mapping, rather than during the reduction. it is possible to use the two parameter form of reduce( ) to compute the product

Example This example uses map( ) to create a new stream that contains only selected fields from the original stream In this case, the original stream contains objects of type NamePhoneEmail which contains names, phone numbers, and e-mail addresses The program then maps only the names and phone numbers to a new stream of NamePhone objects The e-mail addresses are discarded

class NamePhoneEmail // Use map() to create a new stream that contains only // selected aspects of the original stream. import java.util.*; import java.util.stream.*; class NamePhoneEmail { String name; String phonenum; String email; NamePhoneEmail(String n, String p, String e) { name = n; phonenum = p; email = e; }

class NamePhone class NamePhone { String name; String phonenum; NamePhone(String n, String p) { name = n; phonenum = p; }

class StreamDemo4 class StreamDemo5 { public static void main(String[] args) { // A list of names, phone numbers, and e-mail addresses. ArrayList<NamePhoneEmail> myList = new ArrayList<>( ); myList.add(new NamePhoneEmail("Larry", "555-5555", "Larry@HerbSchildt.com")); myList.add(new NamePhoneEmail("James", "555-4444", "James@HerbSchildt.com")); myList.add(new NamePhoneEmail("Mary", "555-3333", "Mary@HerbSchildt.com")); System.out.println("Original values in myList: "); myList.stream().forEach( (a) -> { System.out.println(a.name + " " + a.phonenum + " " + a.email); }); System.out.println();

class StreamDemo4 (cont.) // Map just the names and phone numbers to a new stream. Stream<NamePhone> nameAndPhone = myList.stream().map( (a) -> new NamePhone(a.name,a.phonenum) ); System.out.println("List of names and phone numbers: "); nameAndPhone.forEach( (a) -> { System.out.println(a.name + " " + a.phonenum); }); }

Output Original values in myList: Larry 555-5555 Larry@HerbSchildt.com James 555-4444 James@HerbSchildt.com Mary 555-3333 Mary@HerbSchildt.com List of names and phone numbers: Larry 555-5555 James 555-4444 Mary 555-3333

Mapping (cont.) as more than one intermediate operation can be pipelined together E.g.: the following statement uses filter( ) and then map( ) to produce a new stream that contains only the name and phone number of the elements with the name "James": Stream<NamePhone> nameAndPhone = myList.stream(). filter((a) -> a.name.equals("James")). map((a) -> new NamePhone(a.name,a.phonenum));

Mapping (cont.) three other versions of map( ) are provided. They return a primitive stream, as shown here: IntStream mapToInt(ToIntFunction<? super T> mapFunc) LongStream mapToLong(ToLongFunction<? super T> mapFunc) DoubleStream mapToDouble(ToDoubleFunction<? super T> mapFunc) Each mapFunc must implement the abstract method defined by the specified interface, returning a value of the indicated type E.g.:, ToDoubleFunction specifies applyAsDouble(T val ) method - return the value of its parameter as a double

Example this example uses a primitive stream It first creates an ArrayList of Double values ,It then uses stream( ) followed by mapToInt( ) to create an IntStream that contains the ceiling of each value

class StreamDemo6 // Map a Stream to an IntStream. import java.util.*; import java.util.stream.*; class StreamDemo6 { public static void main(String[] args) { // A list of double values. ArrayList<Double> myList = new ArrayList<>( ); myList.add(1.1); myList.add(3.6); myList.add(9.2); myList.add(4.7); myList.add(12.1); myList.add(5.0);

class StreamDemo6 (cont.) System.out.print("Original values in myList: "); myList.stream().forEach( (a) -> { System.out.print(a + " "); }); System.out.println(); // Map the ceiling of the elements in myList to an IntStream. IntStream cStrm = myList.stream().mapToInt((a) -> (int) Math.ceil(a)); System.out.print("The ceilings of the values in myList: "); cStrm.forEach( (a) -> { }

Output Original values in myList: 1.1 3.6 9.2 4.7 12.1 5.0 The ceilings of the values in myList: 2 4 10 5 13 5

Explanations The stream produced by mapToInt( ) contains the ceiling values of the original elements in myList

Mapping (cont.) the stream API also provides methods that support flat maps These are flatMap( ), flatMapToInt( ), flatMapToLong( ), and flatMapToDouble( ) designed to handle situations: each element in the original stream is mapped to more than one element in the resulting stream

Collecting obtain a collection from a stream the stream API - collect( ) method - two forms one of them: <R, A> R collect(Collector<? super T, A, R> collectorFunc) R specifies the type of the result T specifies the element type of the invoking stream The internal accumulated type is specified by A. collectorFunc specifies how the collection process works. The collect( ) method is a terminal operation

Collecting (cont.) Collectors class, in packagejava.util.stream. defines a number of static collector methods can be used as-is The two are toList( ) and toSet( ), shown here: static <T> Collector<T, ?, List<T>> toList( ) static <T> Collector<T, ?, Set<T>> toSet( ) The toList( ) method returns a collector that can be used to collect elements into a List The toSet( ) method returns a collector that can be used to collect elements into a Set E.g.:, to collect elements into a List: collect(Collectors.toList())

Example The following program puts the preceding discussion into action It reworks the example in the previous section so that it collects the names and phone numbers into a List and a Set

class NamePhoneEmail // Use collect() to create a List and a Set from a stream. import java.util.*; import java.util.stream.*; class NamePhoneEmail { String name; String phonenum; String email; NamePhoneEmail(String n, String p, String e) { name = n; phonenum = p; email = e; }

class NamePhone class NamePhone { String name; String phonenum; NamePhone(String n, String p) { name = n; phonenum = p; }

class StreamDemo7 class StreamDemo7 { public static void main(String[] args) { // A list of names, phone numbers, and e-mail addresses. ArrayList<NamePhoneEmail> myList = new ArrayList<>( ); myList.add(new NamePhoneEmail("Larry", "555-5555", "Larry@HerbSchildt.com")); myList.add(new NamePhoneEmail("James", "555-444","James@HerbSchildt.com")); myList.add(new NamePhoneEmail("Mary", "555-3333", "Mary@HerbSchildt.com")); // Map just the names and phone numbers to a new stream. Stream<NamePhone> nameAndPhone = myList.stream().map( (a) -> new NamePhone(a.name,a.phonenum));

class StreamDemo7 (cont.) // Use collect to create a List of the names and phone numbers. List<NamePhone> npList = nameAndPhone.collect(Collectors.toList()); System.out.println("Names and phone numbers in a List:"); for(NamePhone e : npList) System.out.println(e.name + ": " + e.phonenum);

class StreamDemo7 (cont.) // Obtain another mapping of the names and phone numbers. nameAndPhone = myList.stream().map( (a) -> new NamePhone(a.name,a.phonenum)); // Now, create a Set by use of collect(). Set<NamePhone> npSet = nameAndPhone.collect(Collectors.toSet()); System.out.println("\nNames and phone numbers in a Set:"); for(NamePhone e : npSet) System.out.println(e.name + ": " + e.phonenum); }

Output Names and phone numbers in a List: Larry: 555-5555 James: 555-4444 Mary: 555-3333 Names and phone numbers in a Set:

Explanations following line collects the name and phone numbers into a List using toList( ): List<NamePhone> npList = nameAndPhone.collect(Collectors.toList()); the collection referred to by npList can be used like any other List collection E.g.: for(NamePhone e : npList) System.out.println(e.name + ": " + e.phonenum);

converting streams to arrays streams can be converted to array by calling toArray and get an array of the stream elements. stream.toArray() - returns an Object[] array for an array of the correct type, pass in the array constructor: String[] result = words.toArray(String[]::new); // words.toArray() has type Object[] N