Home > Articles

This chapter is from the book

16.4 Building Streams

A stream must have a data source. In this section we will explore how streams can be created from various data sources: collections, arrays, specified values, generator functions, strings, and I/O channels, among others.

Aspects to Consider When Creating Streams

When creating a stream from a data source, certain aspects to consider include whether the stream is:

  • Sequential or parallel

  • Ordered or unordered

  • Finite or infinite

  • Object or numeric

Sequential or Parallel Stream

A sequential stream is one whose elements are processed sequentially (as in a for loop) when the stream pipeline is executed by a single thread. Figure 16.1 illustrates the execution of a sequential stream, where the stream pipeline is executed by a single thread.

A parallel stream is split into multiple substreams that are processed in parallel by multiple instances of the stream pipeline being executed by multiple threads, and their intermediate results combined to create the final result. Parallel streams are discussed in detail later (p. 1009).

The different ways to create a stream on a data source that are illustrated in this section result in a sequential stream. A parallel stream can only be created directly on a collection by invoking the Collection.parallelStream() method (p. 897).

The sequential or parallel mode of an existing stream can be modified by calling the BaseStream.sequential() and BaseStream.parallel() intermediate operations, respectively (p. 933). A stream is executed sequentially or in parallel depending on the execution mode of the stream on which the terminal operation is initiated.

Ordered or Unordered Stream

The encounter order of a stream refers to the way in which a stream makes its elements available for processing to an operation in a pipeline. For such data sources as a list, the encounter order of the initial stream is the same as the order of the elements in the list, whereas a stream created with a set of values does not have an encounter order, as the elements of a set are considered to be unordered.

The encounter order of a stream may be changed by an intermediate operation. For example, the sorted() operation may impose an encounter order on an unordered stream (p. 929), and the unordered() operation may designate a stream unordered (p. 932). Also, some terminal operations might choose to ignore the encounter order; an example is the forEach() operation (p. 948).

For ordered sequential streams, an identical result is produced when identical stream pipelines are executed on an identical data source—that is, the execution is deterministic. This guarantee does not hold for unordered sequential streams, as the results produced might be different.

Processing of unordered parallel streams may have better performance than for ordered parallel streams in identical stream pipelines when the ordering constraint is removed, as maintaining the order might carry a performance penalty.

Finite or Infinite Stream

The size of a stream can be finite or infinite depending on how the stream is created. The generate() and iterate() methods of the core stream interfaces create streams with an infinite number of elements (p. 894). Such a stream is said to be unbounded. The overloaded ints(), longs(), and doubles() methods of the java.util.Random class create streams with an effectively unlimited number of pseudorandom values (p. 900). An infinite stream must be truncated before the terminal operation is initiated; otherwise, the stream pipeline will never terminate (p. 917).

Object or Numeric Stream

The interface Stream<T> defines the contract for streams of object references—that is, object streams. The specialized interfaces IntStream, LongStream, and DoubleStream represent streams of int, long, and double values, respectively—that is, numeric streams. The various ways to create streams discussed here will always result in a stream whose element type is either a reference type or a numeric type (int, long, or double). Conversion between these stream types is discussed in §16.5, p. 934.

Table 16.1, p. 904, summarizes selected methods for building streams from various data sources.

The following static factory methods for building streams are defined in the Stream<T> class. Counterparts to these methods are also provided by the IntStream, LongStream, and DoubleStream interfaces for creating numeric streams, unless otherwise noted:

The Empty Stream

An empty stream can be obtained by calling the empty() method of the core stream interfaces. As the name implies, such a stream has no elements.

Stream<CD> cdStream = Stream.empty();                   // Empty stream of CD.
System.out.println("Count: " + cdStream.count());       // Count: 0
IntStream iStream = IntStream.empty();                  // Empty stream of int.
System.out.println("Count: " + iStream.count());        // Count: 0

The count() method is a terminal operation in the Stream<T> interface (p. 953). It returns the number of elements processed through the stream pipeline.

Using the null value to indicate that a stream is empty may result in a NullPointer-Exception. Therefore, using an explicit empty stream is highly recommended.

Streams from Specified Values

The two overloaded of() methods in the core stream interfaces create finite sequential ordered streams from data values that are specified as arguments.

In the code below, the single-argument of() method is called at (1), and the variable arity of() method is called at (2), both creating a stream of element type CD. The size of the streams created at (1) and (2) is 1 and 3, respectively. The stream pipeline comprising (3) and (4) filters the pop music CDs and prints their title at (4). The forEach() terminal operation at (4) applies its Consumer action to each pop music CD.

// From specified objects.
Stream<CD> cdStream1 = Stream.of(CD.cd0);                  // (1) Single-arg call.
Stream<CD> cdStream2 = Stream.of(CD.cd0, CD.cd1, CD.cd2);  // (2) Varargs call.
cdStream2.filter(CD::isPop)                                // (3)
         .forEach(cd -> System.out.println(cd.title()));   // (4)

The code below shows examples of using numeric values to create streams. The values specified at (1) and (2) are autoboxed to create a stream of objects. The declaration statements at (3) and (4) avoid the overhead of autoboxing when streams of numeric values are created. However, at (4), an implicit numeric conversion to double is applied to the non-double values.

// From specified numeric values.
Stream<Integer> integerStream1 = Stream.of(2017, 2018, 2019);        // (1)
Stream<? extends Number> numStream = Stream.of(100, 3.14D, 5050L);   // (2)
IntStream intStream1 = IntStream.of(2017, 2018, 2019);               // (3)
DoubleStream doubleStream = DoubleStream.of(100, 3.14D, 5050L);      // (4)

The variable arity of() method can be used to create a stream whose source is an array. Equivalently, the overloaded Arrays.stream() method can be used for the same purpose. In all cases below, the size of the stream is the same as the size of the array, except at (7). An int array is an object that is passed to the single-argument Stream.Of() method (creating a Stream<int[]>), and not the variable arity Stream.of() method. The int array is, however, passed to the variable arity IntStream.of() method at (8). Creating a stream from a numeric array is safer with the numeric stream interfaces or the Arrays.stream() method than the Stream.of() method.

// From an array of CDs.
Stream<CD> cdStream3 = Stream.of(CD.cdArray);                 // (1)
Stream<CD> cdStream4 = Arrays.stream(CD.cdArray);             // (2)

// From an array of Integer.
Integer[] integerArray = {2017, 2018, 2019};                  // (3)
Stream<Integer> integerStream2 = Stream.of(integerArray);     // (4)
Stream<Integer> integerStream3 = Arrays.stream(integerArray); // (5)

// From an array of int.
int[] intArray = {2017, 2018, 2019};                          // (6)
Stream<int[]> intArrayStream = Stream.of(intArray);           // (7) Size is 1.
IntStream intStream2 = IntStream.of(intArray);                // (8) Size is 3.
IntStream intStream3 = Arrays.stream(intArray);               // (9) Size is 3.

The Stream.of() methods throw a NullPointerException if the argument is null. The ofNullable() method, on the other hand, returns an empty stream if this is the case; otherwise, it returns a singleton stream.

Using Generator Functions to Build Infinite Streams

The generate() and iterate() methods of the core stream interfaces can be used to create infinite sequential streams that are unordered or ordered, respectively.

Infinite streams need to be truncated explicitly in order for the terminal operation to complete execution, or the operation will not terminate. Some stateful intermediate operations must process all elements of the streams in order to produce their results—for example, the sort() intermediate operation (p. 929) and the reduce() terminal operation (p. 955). The limit(maxSize) intermediate operation can be used to limit the number of elements that are available for processing from a stream (p. 917).

Generate

The generate() method accepts a supplier that generates the elements of the infinite stream.

IntSupplier supplier = () -> (int) (6.0 * Math.random()) + 1;  // (1)
IntStream diceStream = IntStream.generate(supplier);           // (2)
diceStream.limit(5)                                            // (3)
          .forEach(i -> System.out.print(i + " "));            // (4) 2 4 5 2 6

The IntSupplier at (1) generates a number between 1 and 6 to simulate a dice throw every time it is executed. The supplier is passed to the generate() method at (2) to create an infinite unordered IntStream whose values simulate throwing a dice. In the pipeline comprising (3) and (4), the number of values in the IntStream is limited to 5 at (3) by the limit() intermediate operation, and the value of each dice throw is printed by the forEach() terminal operation at (4). We can expect five values between 1 and 6 to be printed when the pipeline is executed.

Iterate

The iterate() method accepts a seed value and a unary operator. The method generates the elements of the infinite ordered stream iteratively: It applies the operator to the previous element to generate the next element, where the first element is the seed value.

In the code below, the seed value of 1 is passed to the iterate() method at (2), together with the unary operator uop defined at (1) that increments its argument by 2. The first element is 1 and the second element is the result of the unary operator applied to 1, and so on. The limit() operation limits the stream to five values. We can expect the forEach() operation to print the first five odd numbers.

IntUnaryOperator uop = n -> n + 2;                // (1)
IntStream oddNums = IntStream.iterate(1, uop);    // (2)
oddNums.limit(5)
       .forEach(i -> System.out.print(i + " "));  // 1 3 5 7 9

The following stream pipeline will really go bananas if the stream is not truncated by the limit() operation:

Stream.iterate("ba", b -> b + "na")
      .limit(5)
      .forEach(System.out::println);

Concatenating Streams

The concat() method creates a resulting stream where the elements from the first argument stream are followed by the elements from the second argument stream. The code below illustrates this operation for two unordered sequential streams. Two sets are created at (1) and (2) based on lists of strings that are passed to the set constructors. The two streams created at (3) and (4) are unordered, since they are created from sets (p. 897). These unordered streams are passed to the concat() method at (5). The resulting stream is processed in the pipeline comprising (5) and (6). The forEachOrdered() operation at (6) respects the encounter order of the stream if it has one—that is, if it is ordered (p. 948). The output confirms that the resulting stream is unordered.

Set<String> strSet1                                                         // (1)
    = Set.of("All", " objects", " are", " equal");
Set<String> strSet2                                                         // (2)
    = Set.of(" but", " some", " are", " more", " equal", " than", " others.");
Stream<String> unorderedStream1 = strSet1.stream();                         // (3)
Stream<String> unorderedStream2 = strSet2.stream();                         // (4)
Stream.concat(unorderedStream1, unorderedStream2)                           // (5)
      .forEachOrdered(System.out::print);                                      // (6)
// objectsAll equal are some are others. than equal more but

The resulting stream is ordered if both argument streams are ordered. The code below illustrates this operation for two ordered sequential streams. The two streams created at (1) and (2) below are ordered. The ordering is given by the specification order of the strings as arguments to the Stream.of() method. These ordered streams are passed to the concat() method at (3). The resulting stream is processed in the pipeline comprising (3) and (4). The output confirms that the resulting stream is ordered.

Stream<String> orderedStream1 = Stream.of("All", " objects",                // (1)
                                          " are", " equal");
Stream<String> orderedStream2 = Stream.of(" but", " some", " are", " more", // (2)
                                          " equal", " than", " others.");
Stream.concat(orderedStream1, orderedStream2)                               // (3)
      .forEachOrdered(System.out::print);                                   // (4)
// All objects are equal but some are more equal than others.

As far as the mode of the resulting stream is concerned, it is parallel if at least one of the constituent streams is parallel. The code below illustrates this behavior.

The parallel() intermediate operation used at (1) returns a possibly parallel stream (p. 933). The call to the isParallel() method confirms this at (2). We pass one parallel stream and one sequential stream to the concat() method at (3). The call to the isParallel() method at (4) confirms that the resulting stream is parallel. The printout from (5) shows that it is also unordered. Note that new streams are created on the sets strSet1 and strSet2 at (1) and (3), respectively, as we cannot reuse the streams that were created earlier and consumed.

Stream<String> pStream1 = strSet1.stream().parallel();                // (1)
System.out.println("pStream1 is parallel: " + pStream1.isParallel()); // (2) true
Stream<String> rStream = Stream.concat(pStream1, strSet2.stream());   // (3)
System.out.println("rStream is parallel: " + pStream1.isParallel());  // (4) true
rStream.forEachOrdered(System.out::print);                            // (5)
// objectsAll equal are some are others. than equal more but

Streams from Collections

The default methods stream() and parallelStream() of the Collection interface create streams with collections as the data source. Collections are the only data source that provide the parallelStream() method to create a parallel stream directly. Otherwise, the parallel() intermediate operation must be used in the stream pipeline.

The following default methods for building streams from collections are defined in the java.util.Collection interface:

We have already seen examples of creating streams from lists and sets, and several more examples can be found in the subsequent sections.

The code below illustrates two points about streams and their data sources. If the data source is modified before the terminal operation is initiated, the changes will be reflected in the stream. A stream is created at (2) with a list of CDs as the data source. Before a terminal operation is initiated on this stream at (4), an element is added to the underlying data source list at (3). Note that the list created at (1) is modifiable. The count() operation correctly reports the number of elements processed in the stream pipeline.

List<CD> listOfCDS = new ArrayList<>(List.of(CD.cd0, CD.cd1));       // (1)
Stream<CD> cdStream = listOfCDS.stream();                            // (2)
listOfCDS.add(CD.cd2);                                               // (3)
System.out.println(cdStream.count());                                // (4) 3
// System.out.println(cdStream.count());             // (5) IllegalStateException

Trying to initiate an operation on a stream whose elements have already been consumed results in a java.lang.IllegalStateException. This case is illustrated at (5). The elements in the cdStream were consumed after the terminal operation at (4). A new stream must be created on the data source before any stream operations can be run.

To create a stream on the entries in a Map, a collection view can be used. In the code below, a Map is created at (1) and populated with some entries. An entry view on the map is obtained at (2) and used as a data source at (3) to create an unordered sequential stream. The terminal operation at (4) returns the number of entries in the map.

Map<Integer, String> dataMap = new HashMap<>();                     // (1)
dataMap.put(1, "en"); dataMap.put(2, "to");
dataMap.put(3, "tre"); dataMap.put(4, "fire");
long numOfEntries = dataMap
    .entrySet()                                                     // (2)

    .stream()                                                       // (3)
    .count();                                                       // (4) 4

In the examples in this subsection, the call to the stream() method can be replaced by a call to the parallelStream() method. The stream will then execute in parallel, without the need for any additional synchronization code (p. 1009).

Streams from Arrays

We have seen examples of creating streams from arrays when discussing the variable arity of() method of the stream interfaces and the overloaded Arrays.stream() methods earlier in the chapter (p. 893). The sequential stream created from an array has the same order as the positional order of the elements in the array. As far as numeric streams are concerned, only an int, long, or double array can act as the data source of such a stream.

The code below illustrates creating a stream based on a subarray that is given by the half-open interval specified as an argument to the Array.stream() method, as shown at (1). The stream pipeline at (2) calculates the length of the subarray.

Stream<CD> cdStream = Arrays.stream(cdArray, 1, 4);          // (1)
long noOfElements = cdStream.count();                        // (2) 3

The following overloaded static methods for building sequential ordered streams from arrays are defined in the java.util.Arrays class:

Building a Numeric Stream with a Range

The overloaded methods range() and rangeClosed() can be used to create finite ordered streams of integer values based on a range that can be half-open or closed, respectively. The increment size is always 1.

The following static factory methods for building numeric streams are defined only in the IntStream and LongStream interfaces in the java.util.stream package.

The range(startInclusive, endExclusive) method is equivalent to the following for(;;) loop:

for (int i = startInclusive; i < endExclusive; i++) {
  // Loop body.
}

When processing with ranges of integer values, the range() methods should also be considered on par with the for(;;) loop.

The stream pipeline below prints all the elements in the CD array in reverse. Note that no terminating condition or increment expression is specified. As range values are always in increasing order, a simple adjustment can be done to reverse their order.

IntStream.range(0, CD.cdArray.length)                                   // (1)
         .forEach(i -> System.out.println(cdArray[CD.cdArray.length - 1 - i]));

The following example counts the numbers that are divisible by a specified divisor in a given range of values.

int divisor = 5;
int start = 2000, end = 3000;
long divisibles = IntStream
    .rangeClosed(start, end)                                            // (1)
    .filter(number -> number % divisor == 0)                            // (2)
    .count();                                                           // (3)
System.out.println(divisibles);                                         // 201

The next example creates an int array that is filled with increment values specified by the range at (1) below. The toArray() method is a terminal operation that creates an array of the appropriate type and populates it with the values in the stream (p. 971).

int first = 10, len = 8;
int[] intArray = IntStream.range(first, first + len).toArray();         // (1)
System.out.println(intArray.length + ": " + Arrays.toString(intArray));
//8: [10, 11, 12, 13, 14, 15, 16, 17]

The example below shows usage of two nested ranges to print the multiplication tables. The inner arrange is executed 10 times for each value in the outer range.

IntStream.rangeClosed(1, 10)                                 // Outer range.
         .forEach(i -> IntStream.rangeClosed(1, 10)          // Inner range.
                           .forEach(j -> System.out.printf("%2d * %2d = %2d%n",
                                                           i, j, i * j)));
}

We cordially invite the inquisitive reader to code the above examples in the imperative style using explicit loops. Which way is better is not always that clear-cut.

Numeric Streams Using the Random Class

The following methods for building numeric unordered streams are defined in the java.util.Random class:

The examples below illustrate using a pseudorandom number generator (PRNG) to create numeric streams. The same PRNG can be used to create multiple streams. The PRNG created at (1) will be used in the examples below.

Random rng = new Random();                        // (1)

The int stream created at (2) is an effectively unlimited unordered stream of int values. The size of the stream is limited to 3 by the limit() operation. However, at (3), the maximum size of the stream is specified in the argument to the ints() method. The values in both streams at (2) and (3) can be any random int values. The contents of the array constructed in the examples will, of course, vary.

IntStream iStream = rng.ints();                   // (2) Unlimited, any int value
int[] intArray = iStream.limit(3).toArray();      // Limits size to 3
//[-1170441471, 1070948914, 264046613]
intArray = rng.ints(3).toArray();                 // (3) Size 3, any int value
//[1011448344, -974832344, 816809715]

The unlimited unordered stream created at (4) simulates the dice throw we implemented earlier using the generate() method (p. 895). The values are between 1 and 6, inclusive. The limit() method must be used explicitly to limit the stream. The finite unordered stream created at (5) incorporates the size and the value range.

intArray = rng.ints(1, 7)                         // (4) Unlimited, [1, 6]
              .limit(3)                           // Limits size to 3
              .toArray();                         // [5, 2, 4]

intArray = rng.ints(3, 1, 7)                      // (5) Size 3, [1, 6]
              .toArray();                         // [1, 4, 6]

The zero-argument doubles() method and the single-argument doubles(streamSize) method generate an unlimited and a limited unordered stream, respectively, whose values are between 0.0 and 1.0 (exclusive).

DoubleStream dStream = rng.doubles(3);            // (6) Size 3, [0.0, 1.0)
double[] dArray = dStream.toArray();
//[0.9333794789872794, 0.7037326827186609, 0.2839257522887708]

Streams from a CharSequence

The CharSequence.chars() method creates a finite sequential ordered IntStream from a sequence of char values. The IntStream must be transformed to a Stream<Character> in order to handle the values as Characters. The IntStream.mapToObj() method can be used for this purpose, as shown at (2). A cast is necessary at (2) in order to convert an int value to a char value which is autoboxed in a Character. Conversion between streams is discussed in §16.5, p. 934.

String strSource = "banananana";
IntStream iStream = strSource.chars();                   // (1)
iStream.forEach(i -> System.out.print(i + " "));         // Prints ints.
// 98 97 110 97 110 97 110 97 110 97

strSource.chars()
         .mapToObj(i -> (char)i)                         // (2) Stream<Character>
         .forEach(System.out::print);                    // Prints chars.
// banananana

The following default method for building IntStreams from a sequence of char values (e.g., String and StringBuilder) is defined in the java.lang.CharSequence interface (§8.4, p. 444):

Streams from a String

The following method of the String class can be used to extract text lines from a string:

In the code below, the string at (1) contains three text lines separated by the line terminator (\n). A stream of element type String is created using this string as the source at (2). Each line containing the word "mistakes" in this stream is printed at (3).

String inputLines = "Wise men learn from their mistakes.\n"                 // (1)
                  + "But wiser men learn from the mistakes of others.\n"
                  + "And fools just carry on.";
Stream<String> lStream = inputLines.lines();                                // (2)
lStream.filter(l -> l.contains("mistakes")).forEach(System.out::println);   // (3)

Output from the code:

Wise men learn from their mistakes.
But wiser men learn from the mistakes of others.

Streams from a BufferedReader

A BufferedReader allows contents of a text file to be read as lines. A line is a sequence of characters terminated by a line terminator sequence. Details of using a Buffered-Reader are covered in §20.3, p. 1251. A simple example of creating streams on text files using a BufferedReader is presented below.

At (1) and (2) in the header of the try-with-resources statement (§7.7, p. 407), a BufferedReader is created to read lines from a given file, and a stream of String is created at (3) by the lines() method provided by the BufferedReader class. These declarations are permissible since both the buffered reader and the stream are Auto-Closeable. Both will be automatically closed after the try block completes execution. A terminal operation is initiated at (4) on this stream to count the number of lines in the file. Of course, each line from the stream can be processed depending on the problem at hand.

try ( FileReader fReader = new FileReader("CD_Data.txt");         // (1)
      BufferedReader bReader = new BufferedReader(fReader);       // (2)
      Stream<String> lStream = bReader.lines() ) {                // (3)
  System.out.println("Number of lines: " + lStream.count());      // (4) 13
} catch (FileNotFoundException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

The following method for building a Stream<String> from a text file is defined in the java.io.BufferedReader class:

Streams from Factory Methods in the Files Class

A detailed discussion of the NIO2 File API that provides the classes for creating the various streams for reading files, finding files, and walking directories in the file system can be found in Chapter 21, p. 1285.

Analogous to the lines() method in the BufferedReader class, a static method with the same name is provided by the java.nio.file.Files class that creates a stream for reading the file content as lines.

In the example below, a Path is created at (1) to represent a file on the file system. A stream is created to read lines from the path at (2) in the header of the try-with-resources statement (§7.7, p. 407). As streams are AutoCloseable, such a stream is automatically closed after the try block completes execution. As no character set is specified, bytes from the file are decoded into characters using the UTF-8 charset. A terminal operation is initiated at (3) on this stream to count the number of lines in the file. Again, each line in the stream can be processed as desired.

Path path = Paths.get("CD_Data.txt");                             // (1)
try (Stream<String> lStream = Files.lines(path)) {                // (2)
  System.out.println("Number of lines: " + lStream.count());      // (3) 13
} catch (FileNotFoundException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

The following static methods for building a Stream<String> from a text file are defined in the java.nio.file.Files class:

Summary of Stream Building Methods

Selected methods for building streams from various data sources are listed in Table 16.1. The first column lists the method names and the reference type that provides them. For brevity, the parameters of the methods are omitted. Note that some methods are overloaded. The prefix NumType stands for Int, Long, or Double. A reference is also provided where details about the method can be found. The remaining four columns indicate various aspects of a stream: the type of stream returned by a method, whether the stream is finite or infinite, whether it is sequential or parallel, and whether it is ordered or unordered (p. 891).

Table 16.1 Summary of Stream Building Methods

Method

Returned stream type

Finite/Infinite

Sequential/Parallel

Ordered/Unordered

Stream.empty()

NumTypeStream.empty()

(p. 893)

Stream<T>

NumTypeStream

Finite

Sequential

Ordered

Stream.of()

Stream.ofNullable()

NumTypeStream.of()

(p. 893)

Stream<T>

Stream<T>

NumTypeStream

Finite

Sequential

Ordered

Stream.generate()

NumTypeStream.generate()

(p. 895)

Stream<T>

NumTypeStream

Infinite

Sequential

Unordered

Stream.iterate()

NumTypeStream.iterate

(p. 895)

Stream<T>

NumTypeStream

Infinite

Sequential

Ordered

Stream.concat()

NumTypeStream.concat()

(p. 895)

Stream<T>

NumTypeStream

Finite if both finite

Parallel if either parallel

Ordered if both ordered

Collection.stream()

(p. 897)

Stream<T>

Finite

Sequential

Ordered if collection ordered

Collection.parallelStream()

(p. 897)

Stream<T>

Finite

Parallel

Ordered if collection ordered

Arrays.stream()

(p. 898)

Stream<T>

NumTypeStream

Finite

Sequential

Ordered

IntStream.range()

IntStream.rangeClosed()

LongStream.range()

LongStream.rangeClosed()

(p. 898)

IntStream

IntStream

LongStream

LongStream

Finite

Sequential

Ordered

Random.ints()

Random.longs()

Random.doubles()

(p. 900)

IntStream

LongStream

DoubleStream

Finite or infinite, depending on parameters

Sequential

Unordered

CharSequence.chars()

(p. 901)

IntStream

Finite

Sequential

Ordered

String.lines()

(p. 902)

Stream<String>

Finite

Sequential

Ordered

BufferedReader.lines()

(p. 902)

Stream<String>

Finite

Sequential

Ordered

Files.lines()

(p. 903)

Stream<String>

Finite

Sequential

Ordered

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020