Java’s Stream API.

Slides:



Advertisements
Similar presentations
Programming Languages and Paradigms
Advertisements

Chapter 7 User-Defined Methods. Chapter Objectives  Understand how methods are used in Java programming  Learn about standard (predefined) methods and.
Inheritance Inheritance Reserved word protected Reserved word super
Road Map Introduction to object oriented programming. Classes
COMP 14 Introduction to Programming Miguel A. Otaduy May 25, 2004.
Evan Korth New York University Computer Science I Classes and Objects Professor: Evan Korth New York University.
COMP 14 Introduction to Programming Mr. Joshua Stough February 28, 2005 Monday/Wednesday 11:00-12:15 Peabody Hall 218.
Lecture 2: Design and Implementation of Lambda Expressions in Java 8 Alfred V. Aho CS E6998-1: Advanced Topics in Programming Languages.
Programming II Object Oriented Programming with Java - Advanced Topics - Java 8: Functional Interfaces, Method References and Lambda Expressions Alastair.
Java Unit 9: Arrays Declaring and Processing Arrays.
Week 4-5 Java Programming. Loops What is a loop? Loop is code that repeats itself a certain number of times There are two types of loops: For loop Used.
Lambdas and Streams. Functional interfaces Functional interfaces are also known as single abstract method (SAM) interfaces. Package java.util.function.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
The Java Programming Language
1 Introduction Modules  Most computer programs solve much larger problem than the examples in last sessions.  The problem is more manageable and easy.
5-Aug-2002cse Arrays © 2002 University of Washington1 Arrays CSE 142, Summer 2002 Computer Programming 1
Chapter 6Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 6 l Array Basics l Arrays and Methods l Programming with Arrays.
Server-side Programming The combination of –HTML –JavaScript –DOM is sometimes referred to as Dynamic HTML (DHTML) Web pages that include scripting are.
Working With Objects Tonga Institute of Higher Education.
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
Chapter 5 Classes and Methods II Lecture Slides to Accompany An Introduction to Computer Science Using Java (2nd Edition) by S.N. Kamin, D. Mickunas, E.
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.
Functional Programming IN NON-FUNCTIONAL LANGUAGES.
IAP C# 2011 Lecture 2: Delegates, Lambdas, LINQ Geza Kovacs.
An Introduction to Java – Part 1 Erin Hamalainen CS 265 Sec 001 October 20, 2010.
OOP Basics Classes & Methods (c) IDMS/SQL News
Chapter 9 Introduction to Arrays Fundamentals of Java.
Functional Processing of Collections (Advanced) 6.0.
Lecture 7: Arrays Michael Hsu CSULA 3 Opening Problem Read one hundred numbers, compute their average, and find out how many numbers are above the average.
Inheritance Modern object-oriented (OO) programming languages provide 3 capabilities: encapsulation inheritance polymorphism which can improve the design,
Modern Programming Tools And Techniques-I
The need for Programming Languages
Programming what is C++
Chapter 7 User-Defined Methods.
Functional Programming and Stream API
Taking Java from purely OOP by adding “functional level Programming”
Road Map Introduction to object oriented programming. Classes
The Strategy Pattern II: Emulating Higher-Order Functions
Generics, Lambdas, Reflections
Functional Processing of Collections (Advanced)
Chapter 4 – Control Structures Part 1
Introduction to Functional Programming in Racket
HKCT Java OOP Unit 02 Object Oriented Programming in Java Unit 02 Methods, Classes, and Objects 1.
Functional Programming with Java
Java 8 Java 8 is the biggest change to Java since the inception of the language Lambdas are the most important new addition Java is playing catch-up: most.
.NET and .NET Core 5.2 Type Operations Pan Wuming 2016.
Subroutines Idea: useful code can be saved and re-used, with different data values Example: Our function to find the largest element of an array might.
Unit E Step-by-Step: Programming with Python
תוכנה 1 בשפת Java שיעור מספר 10: חידושים ב Java 8
Streams.
Control Flow Chapter 6.
Conditional Statements
תוכנה 1 בשפת Java שיעור מספר 11: חידושים ב Java 8
Building Java Programs Chapter 19
Type & Typeclass Syntax in function
Building Java Programs Chapter 19
Effective Java, 3rd Edition Chapter 7: Lambdas and Streams
Chapter 6 Arrays.
A few of the more significant changes and additions. James Brucker
Introduction to Functional Programming in Racket
Generics, Lambdas, Reflections
Computer Science 312 Lambdas in Java 1.
Java Programming Language
Object-Oriented Design Part 2
LCC 6310 Computation as an Expressive Medium
Review for Midterm 3.
„Lambda expressions, Optional”
Generics, Lambdas and Reflection
Introduction to Methods and Interfaces
Presentation transcript:

Java’s Stream API

Introduction Given a collection c and a function f, sometime we’d like to create a new collection c’ such that for each element x in c we’ll have f(x) in c’. For instance, we have the collection called intStrings with the following elements: (“1”, “2”, “3”, “4”), and the function Integer::parseInt which takes a string and parse it into an integer. Well, we could of course do the following: List<String> intStrings = Arrays.asList("1", "2", "3", "4"); List<Integer> integers = new ArrayList<>(); for(int i=0; i<intStrings.size(); i++){ int parsed = Integer.parseInt(intStrings.get(i)); integers.add(parsed); }

Introduction This code indeed works as intended and we get a new list, called “integers” with the elements (1, 2, 3, 4). However, as the amount of code and complexity of tasks scales up, such programming style can hurt our code’s readability. Instead, what if we could tell our collection to simply apply that function on each of it’s elements? Fortunately, we can do this, using the java Stream API! List<String> intStrings = Arrays.asList("1", "2", "3", "4"); List<Integer> integers = intStrings.stream() .map(Integer::parseInt) .collect(Collectors.toList());

Introduction Functional programming is a programming paradigm – a style of building the structure and elements of computer program. Treats computation as the evaluation of mathematical functions. Avoids changing-state and mutable data. A different approach than the object oriented programming which relies on the object’s state.

Functional vs Imperative Programming Characteristic Imperative approach Functional approach Programmer focus How to perform tasks (algorithms) and how to track changes in state What information is desired and what transformations are required? State changes Important Almost non-existent Order of execution Low importance Primary flow control Loops, conditionals and function calls Function calls, including recursion Primary manipulation unit Instances of structures or classes Functions as first-class objects and data collections

Anonymous Class Definition: An anonymous class is a class that have no name. Allows declaring and instantiating a class at the same time. An anonymous inner class can be useful when making an instance of an object with certain “extras” such as overloading methods of a class or interface, without having to actually subclass a class. A drawback with anonymous classes is they can't have explicit constructors. You can't pass them any parameters when they are instantiated. One of the key benefits of an anonymous class is encapsulation.

Anonymous Class For instance: public interface Printer { void print(); } public static void main(String[] args){ Printer p1 = new Printer() { @Override public void print() { System.out.println("This is a message from p1"); } }; Printer p2 = new Printer() { @Override public void print() { System.out.println("This is a message from p2."); } }; }

Lambda Expressions Definition: A lambda expression is a block of code that is treated as an object. It can be passed as an argument to another function, or used for constructing the return value of a function. In java: lambda expressions are just a simpler way of instantiating an anonymous class. We use the following syntax to instantiate a lambda expression: (<arg 1>, …, <arg n>) -> <returned expression>; (<arg 1>, …, <arg n>) -> { <expr 1>; … <expr n>; return <expr>; };

Lambda Expressions In the following example: Adder is an interface with the method ‘perform’ that takes an Integer and returns an Integer. “add1” is an anonymous class that implements adder. “_add1” is an equivalent lambda expression. We can call ‘add1.perform(x)’ which returns x+1. public interface Adder { int perform(int x); } public static void main(String[] args){ Adder add1 = new Adder() { @Override public int perform(int x) { return x+1; } }; Adder _add1 = x -> x+1; } int y = add1.perform(3);

Functions as variables / parameters Some languages allows passing function as parameters to another functions, or instantiate functions as variables. This is supported by some languages (including C, C++ and C#) The famous Language-Integrated-Query (LINQ) of C# provides a simple mechanism, very similar to java’s stream. Both C and C++ allows the programmer to treat functions as variables. This mechanism works similarly in modern languages like python and javascript.

In Java In java we don’t really pass functions as arguments. Instead we use interfaces with a single method. Anonymous classes with a single method can be turned into lambda expressions. It’s called Syntactic Sugar. Java simulates its lambda expressions and functional interface in an object-oriented style, as form of abstraction.

In Java Take a look at the previous example of anonymous class: The anonymous ‘new Printer()…’ can be replaced with the following equal lambda expression: Hint: your Intellij will suggest by default to replace anonymous classes with lambda expressions when possible. public interface Printer { void print(); } Printer p = new Printer() { @Override public void print() { System.out.println("Hello world!"); } }; Printer p = () -> System.out.println("Hello world!");

The functional interface Basic entities you should know: Supplier<T> Simulates a method that takes no arguments and returns T by calling get(). Consumer<T> Simulates a void method that takes an argument of type T by calling accept(T) public interface Supplier<T> { T get(); } public interface Consumer<T> { void accept(T t); }

The functional interface Basic entities you should know: Function<T, K> Simulates a method that takes an argument of type T and returns a value of type K by calling apply(T) Predicate<T> Simulates a method that takes an argument of type T and returns a boolean indicating whether T matches some specifications by calling test(T). public interface Function<T, R> { R apply(T t); } public interface Predicate<T> { boolean test(T t); }

The Stream API Stream is an API (Application Programming Interface) that supports functional- style operation on streams (or collections) of elements. Intermediate operations (such as map, filter, sorted) allows to perform manipulation on the stream object. Terminal operations (collect, forEach, reduce) allows to aggregate the elements of a manipulated stream into the desired result. Let’s take a look at some of these operations. Assuming the following definition: List<Integer> lst = Arrays.asList(1, 2, 3, 4, 5);

Stream.map() map(f) - Takes a lambda expression f as an argument. f is an object of type Function<T, K>: takes T as an argument and returns K (can be anything). Returns a stream of elements composed of f(x) for each x in lst. Stream<Integer> squared = lst.stream() .map((x) -> x * x); // Values are: (1, 4, 9, 16, 25)

Stream.filter() filter(f) - Takes a lambda expression f as an argument. F is an object of type Predicate<T>: takes T as an argument and returns a boolean, indicating whether that argument matches the predicate. Returns a stream of elements composed of each x in lst such that f(x)=true. Stream<Integer> even = lst.stream() .filter((x) -> x % 2 == 0); // Values are (2, 4)

Stream.reduce() reduce(id, f) - Takes an element id, and a lambda expression f as an argument. id is an object of the same type T of lst. f takes two arguments: accumulate element (starts with id) and the next element of the list (both of the same type T), perform an operation on both of them and return the result (also of type T), which in turn becomes the accumulated value of the next iteration. Returns the accumulated element once done. int sum = lst.stream() .reduce(0, (acc, next) -> acc + next); // Value is 15

Stream.forEach() forEach(f) - Takes a lambda expression f as an argument. f is an object of type Consumer<T>: takes an element T from the stream and perform some operations. No value returned. Equivalent to our famous ‘for x : lst’ loops. We can achieve the same goal by using method-reference: lst.stream().forEach((x) -> System.out.println(x)); // Prints the elements of lst lst.stream().forEach(System.out::println);

Few examples Take a look at the following class for practice: public class Character { String name; String title; String city; int level; double hitPoints; Continent continent; public Character(String name, String title, String city, int level, double hitPoints, Continent continent) { this.name = name; this.title = title; this.city = city; this.level = level; this.hitPoints = hitPoints; this.continent = continent; } } enum Continent { Kalimdor, Eastern_Kingdoms, Northrend } Take a look at the following class for practice: And initialize the following list within our main: List<Character> characters = Arrays.asList( new Character("Arthas Menethil", "Lich King", "Icecrown", 80, 1500, Continent.Northrend), new Character("Thrall", "Warchief", "Orgrimmar", 90, 1200, Continent.Kalimdor), new Character("Jaina Proudmoore", “Lord Admiral", "Theramore", 120, 1000, Continent.Eastern_Kingdoms), new Character("Tyrande Whisperwind", "Priestess of Elune", "Teldrassil", 120, 1100, Continent.Kalimdor), new Character("Sylvanas Windrunner", "Dark Ranger", "Undercity", 120, 1100, Continent.Eastern_Kingdoms) );

Few examples Create a list with the names of all the characters from the continent of Kalimdor: List<String> names = characters.stream() .filter((x) -> x.getContinent() == Continent.Kalimdor) .map(Character::getName) .collect(Collectors.toList()); Note that in order to create a list out of a stream we need to call: .collect(Collectors.toList())

Few examples Find the average hit points of characters at level 120: List<Double> hitPoints = characters.stream() .filter((character) -> character.getLevel() == 120) .map(Character::getHitPoints) .collect(Collectors.toList()); double average = hitPoints.stream() .reduce(0.0, (acc, next) -> acc + next / hitPoints.size());

Few examples Print all characters, sorted by their hit points: characters.stream() .sorted(Comparator.comparing(Character::getHitPoints)) .forEach(System.out::println); Note: we might want to implement Character::toString in order to get an informative result. Also note the usage of ‘Comparator.comparing’: this allows us to compare two object of type Character without actually implementing the ‘Comparable’ interface – useful when you would like to compare elements based on different attributes.

Few examples Given a list of names, initialize a list of characters with the same name, title ‘Grunt’, city ‘Orgrimmar’, level 15, continent ‘Kalimdor’ and hit points between 200 to 300: List<String> gruntsNames = Arrays.asList("Durotan", "Grom", "Garrosh", "Garona", "Nazgrim", "Varok"); List<Character> grunts = gruntsNames.stream() .map((name) -> new Character(name, "Grunt", "Orgrimmar", 15, (Math.random() * 100 + 200), Continent.Kalimdor)) .collect(Collectors.toList());