# Notes
# Streams API Interface
# Lambda Expressions
3 ways to execute
Comparator<Employee> byAge = | |
(Employee emp1, Employee emp2) -> emp1.getAge() - emp2.getAge(); | |
List<Employee> emps = fetchMembers(); | |
emps.sort(byAge); | |
List<Employee> emps = fetchMembers(); | |
emps.sort((Employee emp1, Employee emp2) -> emp1.getAge() - emp2.getAge()); | |
List<Employee> emps = fetchMembers(); | |
emps.sort((emp1, emp2) -> emp1.getAge() - emp2.getAge()); |
Lambdas or Anonymous functions.
# Syntax
lambda operator -> body
where lambda operator can be...
Zero parameter:
() -> System.out.println("Zero parameter lambda");
One parameter:
(p) -> System.out.println("One parameter: " + p);
It is not mandatory to use parentheses, if the type of that variable can be inferred from the contextMultiple parameters :
(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);
// A Java program to demonstrate simple lambda expressions | |
import java.util.ArrayList; | |
class Test { | |
public static void main(String args[]) { | |
// Creating an ArrayList with elements {1, 2, 3, 4} | |
ArrayList<Integer> arrL = new ArrayList<Integer>(); | |
arrL.add(1); | |
arrL.add(2); | |
arrL.add(3); | |
arrL.add(4); | |
// Using lambda expression to print all elements of arrL | |
arrL.forEach(n -> System.out.print(n + " ")); | |
// Using lambda expression to print even elements of arrL | |
arrL.forEach(n -> { if (n%2 == 0) System.out.print(n + " "); }); | |
} | |
} |
Output
1 2 3 4 2 4
# Stream API functionality
Streams can be obtained in a number of ways.
Some examples include:
- From a Collection via the
stream()
- From an array via
Arrays.stream(Object[])
;
Package => java.util.stream
Classes used to support functional-style operations on streams of elements, such as map-reduce transformations on collections.
用于支持对元素流进行功能样式操作的类,例如集合上的 map-reduce 转换。
For example:
int sum = widgets.stream() | |
.filter(b -> b.getColor() == RED) | |
.mapToInt(b -> b.getWeight()) | |
.sum(); |
# Operations and pipelines
A stream is a limitless iterator that allows you to process collections.
流是无限的迭代器,可以处理集合。
Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines or chained operations. The pipeline usually takes the form of map-filter-reduce
pattern.
流操作分为中间操作和终端操作,结合在一起以形成流管道或链接操作。 管道通常采用 map-filter-reduce 模式的形式。
The .map()
method is not an associative data structure, rather it is a transformative operation. It takes a Stream<T>
and it returns either a Stream<T>
or Stream<U>
..map()
方法不是关联数据结构,而是一种转换操作。 它采用 Stream <T>,并返回 Stream <T > 或 Stream <U>。
Example: Stream<String>
to Stream<String>
Example: Stream<String>
to Stream<Date>
A stream pipeline consists of a source (such as a Collection or an array); followed by zero or more intermediate operations such as Stream.filter
or Stream.map
; and a terminal operation such as Stream.forEach
or Stream.reduce
.
流管道由一个源(例如 Collection 或数组)组成; 随后是零个或多个中间操作,例如 Stream.filter
或 Stream.map
; 以及诸如 Stream.forEach
或 Stream.reduce
之类的终端操作。
- Intermediate operations
- return a new stream. They are always lazy; executing an intermediate operation such as
filter()
does not actually perform any filtering, but instead creates a new stream. Some method examples follow:
中间操作返回一个新的流。 它们总是懒惰的。 执行诸如filter()
之类的中间操作实际上并不执行任何过滤,而是创建一个新的流。 一些方法示例如下:peek()
methodmap()
methodfilter()
method - Terminal operations
- such as
Stream.forEach
orIntStream.sum
, may traverse the stream to produce a result or a side-effect. After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer be used. Example methods follow:
诸如Stream.forEach
或IntStream.sum
之类的终端操作,可能会遍历该流以产生结果或副作用。 执行终端操作后,流管线被视为已消耗,无法再使用。 示例方法如下:forEach()
methodcount()
methodmax()
methodcollect()
methodreduce()
method
# Ex use cases
- map
- The map method is used to map the items in the collection to other objects according to the Function passed as argument.
用于根据作为参数传递的 Function,将集合中的项目映射到其他对象。
List number = Arrays.asList(2,3,4,5); | |
List square = number.stream().map(x -> x*x).collect(Collectors.toList()); |
- filter
- The filter method is used to select elements as per the Predicate passed as argument.
根据作为参数传递的词,进行元素选择。
List names = Arrays.asList("Reflection","Collection","Stream"); | |
List result = names.stream().filter(s->s.startsWith("S")).collect(Collectors.toList()); |
- sorted
- The sorted method is used to sort the stream.
用于对流进行排序。
List names = Arrays.asList("Reflection","Collection","Stream"); | |
List result = names.stream().sorted().collect(Collectors.toList()); |
// applying 12% VAT on each purchase | |
// Without lambda expressions: | |
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); | |
for (Integer cost : costBeforeTax) { | |
double price = cost + .12*cost; | |
System.out.println(price); | |
} | |
// With Lambda expression: | |
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); | |
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println); |
Output
112.0
224.0
336.0
448.0
560.0
112.0
224.0
336.0
448.0
560.0
// Applying 12% VAT on each purchase | |
// Old way: | |
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); | |
double total = 0; | |
for (Integer cost : costBeforeTax) { | |
double price = cost + .12*cost; | |
total = total + price; | |
} | |
System.out.println("Total : " + total); | |
// New way: | |
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); | |
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get(); | |
System.out.println("Total : " + bill); |
Output
Total : 1680.0
Total : 1680.0
// joining list and appending data | |
List<String> l = new ArrayList(Arrays.asList("one", "two")); | |
Stream<String> sl = l.stream(); | |
l.add("three"); | |
String s = sl.collect(joining(" ")); |
# Further uses of Stream API!!
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.List; | |
public class Employees { | |
//put a structure together | |
String name; | |
int rank; | |
//add constructor | |
public Employees(String n, int r){ name=n; rank=r; } | |
public static void main(String[] args) { | |
List<Employees> list = new ArrayList<>(); | |
list.add(new Employees("james papa", 3)); | |
list.add(new Employees("luke papa", 1)); | |
list.add(new Employees("kay papa", 2)); | |
/*Old school coding - sort first then display filtered results | |
Collections.sort(list, new EmployeesSort()); | |
for(Employees e : list) { | |
if(e.rank == 4) | |
System.out.println(e.name + " " + e.rank); | |
} | |
*/ | |
//New school output list - stream alt. and sorted! | |
list.stream() | |
.filter((e) -> (e.rank == 4)) | |
.sorted((a, b) -> a.name.compareTo(b.name)) | |
.forEachOrdered((e) -> { | |
System.out.println(e.name + " " + e.rank); | |
}); | |
} | |
} | |
/* | |
import java.util.Comparator; | |
public class EmployeesSort implements Comparator<Employees>{ | |
//compare by name | |
public int compare(Employees obj1, Employees obj2) { | |
return obj1.name.compareTo(obj2.name); | |
} | |
}*/ |
# Lab
PROJECT
Bank record generationsObjective
To write a program that performs data analysis from class objects created in lab #2.
# PROJECT DESCRIPTION
Bank of IIT is in desperate need of analytics from its clients for its loan application process. Currently records show 600 clients exist and the bank is hoping to expand its clientele and its potential by offering premium loans to deserved grantees.
IIT 银行迫切需要客户对其贷款申请流程进行分析。 目前的记录显示有 600 个客户,该银行希望通过向应得的受赠人提供优质贷款来扩大其客户群和潜力。
Perform the data analysis as follows for this lab.
对该实验室执行以下数据分析。
# Project Details
Add to your existing project files from lab 2, a new class called Records. Have the class extend the BankRecords class to grab hold of its instance methods plus the BankRecords object array.
在 lab2 的项目文件中,添加一个名为Records
的新类。让该类扩展BankRecords
类以获取其实例方法,以及BankRecords
对象数组。Provide at least 2 comparator classes implementing the java.util.Comparator interface for comparing various fields for the following data analysis requirements.
提供至少两个比较器类,这些比较器类实现java.util.Comparator
接口,以比较各个字段,以符合以下数据分析要求。Perform the following analysis requirements and output detail for the Records class.
对Records
类执行以下分析要求和输出详细信息。Display the following data analytics in a coherent manner to the console:
以一致的方式在控制台上显示以下数据分析:
- average income for males vs. females
男性与女性的平均收入- number of females with a mortgage and savings account
拥有抵押和储蓄账户的女性人数- number of males with both a car and 1 child per location
每个地点有汽车和 1 个孩子的男性人数
Write all displayed data to a text file called bankrecords.txt relative to your project path as well. Append your name within the text file at the end of the file plus the date/time.
将所有显示的数据写入一个名为bankrecords.txt
的文本文件中,并保存在相对于您的项目路径的位置。在文件末尾的文本中添加您的姓名以及日期 / 时间。Include for credit, your project files including your .csv file and bankrecords.txt file into a zip file, also your jar (executable) file as well as a separate file, and your snapshots of console output and your bankrecords.txt file plus your source code into a Word doc file.
项目文件(包括.csv 文件和 bankrecords.txt 文件)压缩到 zip 文件中,还包括 jar(可执行)文件也是一个单独的文件。控制台输出快照、bankrecords.txt 文件以及您的源代码转换为 Word doc 文件。
# Objectives
# Example of creating a comparator
For your first analytic response that is to show theaverage income for males vs. females
you may want to create a comparator class to sort by sex
对于第一个分析,即显示男性与女性的平均收入,可能要创建一个比较器类,以按性别排序。
import java.util.Comparator; | |
public class SexComparator implements Comparator<BankRecords> { | |
@Override | |
public int compare(BankRecords o1, BankRecords o2) { | |
// use compareTo to compare strings | |
int result = o1.getSex().compareTo(o2.getSex()); | |
return result; | |
} | |
} |
Think of comparators you can set up with not only a primary sort but secondary sorts as well. Example maybe a female sort as a primary sort and mortgages as a secondary sort, etc.
比较器不仅可以设置一级排序,还可以设置二级排序。 例如,女性排序为主要排序,抵押贷款为次要排序,等等。
Another example here maybe to create a comparator java class for sorting by location…
这里的另一个示例可创建一个比较器 Java 类,以按地点排序…
import java.util.Comparator; | |
public class LocationComparator implements Comparator<BankRecords>{ | |
@Override | |
public int compare(BankRecords o1, BankRecords o2) { | |
// use compareTo to compare strings | |
int result = o1.getRegion().compareTo(o2.getRegion()); | |
return result; | |
} | |
} |
# Call up your comparators in your Records.java file.
在 Records.java 文件中调用比较器。
Ex. in main()
, you can call a series of functions to perform your analytic results.
例如 在 main 函数中,可以调用一系列函数来执行分析结果。
Set up your file to also not only write to the console but to a text file.
将文件设置为不仅要写入控制台,还要写入文本文件。
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.util.Arrays; | |
public class Records extends BankRecords { | |
// create formatted object to write output directly to console & file | |
static FileWriter fw = null; | |
public Records() { | |
try { | |
fw = new FileWriter("bankrecords.txt"); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void main(String[] args) { | |
Records br = new Records(); | |
br.readData(); | |
// call functions to perform analytics | |
AvgComp(); // analyze average income per loc | |
//femsComp(); // female count w. mort/savings accounts | |
//malesComp(); // male counts per loc. w. car & 1 child | |
// *** close out file object ***// | |
try { | |
fw.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static void AvgComp() { | |
Arrays.sort(robjs, new SexComparator()); | |
// set up needed variables to gather counts & income by sex | |
// to determine average income by sex | |
int maleCt = 0, femCt = 0; | |
double maleInc =0, femInc = 0; | |
for (int i = 0; i < robjs.length; i++) { | |
if (robjs[i].getSex().equals("FEMALE")) { | |
++femCt; | |
femInc += robjs[i].getIncome(); | |
} else { | |
//... | |
} | |
} | |
// display resulting averages to console and to file | |
System.out.printf(" ... "); | |
try { | |
fw.write("Avg inc. for Females: $" + (femInc/femCt) ); | |
fw.write("..."); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
Continue in like manner as above to finish up two other method definitions, callable in main().
以上述方式继续完成另外两个方法定义,可在 main 函数中调用。
# code
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.Date; | |
import java.util.HashMap; | |
public class Records extends BankRecords { | |
// create formatted object to write output directly to console & file | |
static FileWriter fw = null; | |
public Records() { | |
try { | |
fw = new FileWriter("bankrecords.txt"); | |
fw.write("Data analytic results:\n"); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void main(String[] args) { | |
Records br = new Records(); | |
br.readData(); | |
System.out.printf("Data analytic results:\n"); | |
// call functions to perform analytics | |
AvgComp(); // analyze average income for males vs. females | |
femsComp(); // female count with mortgage/savings accounts | |
malesComp(); // male counts per loc. w. car & 1 child | |
// *** close out file object ***// | |
try { | |
Date date=new Date(); | |
fw.write("\n\nShuang Liu @ " + date.toString()); | |
fw.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static void AvgComp() { | |
Arrays.sort(robjs, new SexComparator()); | |
// set up needed variables to gather counts & income by sex | |
// to determine average income by sex | |
int maleCt = 0, femCt = 0; | |
double maleInc =0, femInc = 0; | |
for (int i = 0; i < robjs.length; i++) { | |
if (robjs[i].getSex().equals("FEMALE")) { | |
++femCt; | |
femInc += robjs[i].getIncome(); | |
} else { | |
++maleCt; | |
maleInc += robjs[i].getIncome(); | |
} | |
} | |
// display resulting averages to console and to file | |
String femAvg = String.format("\nAverage income for Females: $%.2f", femInc/femCt).toString(); | |
String maleAvg = String.format("\nAverage income for Males: $%.2f", maleInc/maleCt).toString(); | |
System.out.printf(femAvg); | |
System.out.printf(maleAvg); | |
try { | |
fw.write(femAvg); | |
fw.write(maleAvg); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static void femsComp() { | |
Arrays.sort(robjs, new SexComparator()); | |
int femCt = 0; | |
for (int i = 0; i < robjs.length; i++) { | |
if (robjs[i].getSex().equals("FEMALE") | |
&& robjs[i].getMortgage().equals("YES") | |
&& robjs[i].getSave_act().equals("YES")) { | |
++femCt; | |
} | |
} | |
String femNum = "\n\nNum. of Females with Mortgage & saving act: " + femCt + "\n"; | |
System.out.printf(femNum); | |
try { | |
fw.write(femNum); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static void malesComp() { | |
Arrays.sort(robjs, new LocationComparator()); | |
HashMap<String, Integer> map = new HashMap<String, Integer>(); | |
for (int i = 0; i < robjs.length; i++) { | |
if (robjs[i].getSex().equals("MALE") | |
&& robjs[i].getCar().equals("YES") | |
&& robjs[i].getChildren() == 1) { | |
if(map.containsKey(robjs[i].getRegion())) { | |
map.put(robjs[i].getRegion(), map.get(robjs[i].getRegion())+1); | |
} else { | |
map.put(robjs[i].getRegion(), 1); | |
} | |
} | |
} | |
StringBuffer sb = new StringBuffer(); | |
map.forEach((region, count) -> { | |
char[] cs= region.toLowerCase().toCharArray(); | |
cs[0] -= 32; | |
sb.append("\n" + String.valueOf(cs) + " region males with car & 1 child: " + count); | |
}); | |
System.out.printf(sb.toString()); | |
try { | |
fw.write(sb.toString()); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
import java.util.Comparator; | |
public class SexComparator implements Comparator<BankRecords> { | |
@Override | |
public int compare(BankRecords o1, BankRecords o2) { | |
// use compareTo to compare strings | |
int result = o1.getSex().compareTo(o2.getSex()); | |
return result; | |
} | |
} |
import java.util.Comparator; | |
public class LocationComparator implements Comparator<BankRecords>{ | |
@Override | |
public int compare(BankRecords o1, BankRecords o2) { | |
// use compareTo to compare strings | |
int result = o1.getRegion().compareTo(o2.getRegion()); | |
return result; | |
} | |
} |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
public class BankRecords extends Client { | |
//setup static objects for IO processing | |
//array of BankRecords objects | |
static BankRecords robjs[] = new BankRecords[600]; | |
//arraylist to hold spreadsheet rows & columns | |
static ArrayList<List<String>> array = new ArrayList<>(); | |
//instance fields | |
private String id; | |
private int age; | |
private String sex; | |
private String region; | |
private double income; | |
private String married; | |
private int children; | |
private String car; | |
private String save_act; | |
private String current_act; | |
private String mortgage; | |
private String pep; | |
@Override | |
public void readData() { | |
BufferedReader br = null; | |
//initialize reader object and set file path to root of project | |
try { | |
br = new BufferedReader(new FileReader (new File("bank-Detail.csv"))); | |
String line; | |
//read each record in csv file | |
while ((line = br.readLine()) != null) { | |
//parse each record in csv file by a comma ( , ) | |
//into a list stored in the arraylist-> Arrays | |
array.add(Arrays.asList(line.split(","))); | |
} | |
} catch (Exception e) { | |
System.err.println("There was a problem loading the file"); | |
} | |
processData(); //call function for processing record data | |
} | |
@Override | |
public void processData() { | |
//create index for array while iterating thru arraylist | |
int idx=0; | |
//create for each loop to cycle thru arraylist of values | |
//and PASS that data into your record objects' setters | |
for (List<String> rowData: array) { | |
//initialize array of objects | |
robjs[idx] = new BankRecords(); | |
//call setters below and populate them, item by item | |
robjs[idx].setId(rowData.get(0)); //get 1st column | |
robjs[idx].setAge(Integer.parseInt(rowData.get(1))); //get 2nd column | |
robjs[idx].setSex(rowData.get(2)); | |
robjs[idx].setRegion(rowData.get(3)); | |
robjs[idx].setIncome(Double.parseDouble(rowData.get(4))); | |
robjs[idx].setMarried(rowData.get(5)); | |
robjs[idx].setChildren(Integer.parseInt(rowData.get(6))); | |
robjs[idx].setCar(rowData.get(7)); | |
robjs[idx].setSave_act(rowData.get(8)); | |
robjs[idx].setCurrent_act(rowData.get(9)); | |
robjs[idx].setMortgage(rowData.get(10)); | |
robjs[idx].setPep(rowData.get(11)); | |
/*continue processing arraylist item values into each array object -> robjs[] by index*/ | |
idx++; | |
} | |
//printData(); //call function to print objects held in memory | |
} | |
@Override | |
public void printData() { | |
//1. Set appropriate headings for displaying first 25 records | |
//2. Create for loop and print each record objects instance data | |
//3. Within for loop use appropriate formatting techniques to print out record detail | |
//Set heading | |
System.out.printf("First 25 Client details:\n\n%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n", "ID","Age","Sex","Region","Income","Mortgage"); | |
for (int i=0;i<25;i++){ | |
String s=String.format("%-10s\t%-10d\t%-10s\t%-10s\t%-10.2f\t%-10s", | |
robjs[i].getId(),robjs[i].getAge(),robjs[i].getSex(),robjs[i].getRegion(),robjs[i].getIncome(),robjs[i].getMortgage()); | |
System.out.println(s); | |
} | |
} | |
/** | |
* @return the id | |
*/ | |
public String getId() { | |
return id; | |
} | |
/** | |
* @param id the id to set | |
*/ | |
public void setId(String id) { | |
this.id = id; | |
} | |
/** | |
* @return the age | |
*/ | |
public int getAge() { | |
return age; | |
} | |
/** | |
* @param age the age to set | |
*/ | |
public void setAge(int age) { | |
this.age = age; | |
} | |
/** | |
* @return the sex | |
*/ | |
public String getSex() { | |
return sex; | |
} | |
/** | |
* @param sex the sex to set | |
*/ | |
public void setSex(String sex) { | |
this.sex = sex; | |
} | |
/** | |
* @return the region | |
*/ | |
public String getRegion() { | |
return region; | |
} | |
/** | |
* @param region the region to set | |
*/ | |
public void setRegion(String region) { | |
this.region = region; | |
} | |
/** | |
* @return the income | |
*/ | |
public double getIncome() { | |
return income; | |
} | |
/** | |
* @param income the income to set | |
*/ | |
public void setIncome(double income) { | |
this.income = income; | |
} | |
/** | |
* @return the married | |
*/ | |
public String getMarried() { | |
return married; | |
} | |
/** | |
* @param married the married to set | |
*/ | |
public void setMarried(String married) { | |
this.married = married; | |
} | |
/** | |
* @return the children | |
*/ | |
public int getChildren() { | |
return children; | |
} | |
/** | |
* @param children the children to set | |
*/ | |
public void setChildren(int children) { | |
this.children = children; | |
} | |
/** | |
* @return the car | |
*/ | |
public String getCar() { | |
return car; | |
} | |
/** | |
* @param car the car to set | |
*/ | |
public void setCar(String car) { | |
this.car = car; | |
} | |
/** | |
* @return the save_act | |
*/ | |
public String getSave_act() { | |
return save_act; | |
} | |
/** | |
* @param save_act the save_act to set | |
*/ | |
public void setSave_act(String save_act) { | |
this.save_act = save_act; | |
} | |
/** | |
* @return the current_act | |
*/ | |
public String getCurrent_act() { | |
return current_act; | |
} | |
/** | |
* @param current_act the current_act to set | |
*/ | |
public void setCurrent_act(String current_act) { | |
this.current_act = current_act; | |
} | |
/** | |
* @return the mortgage | |
*/ | |
public String getMortgage() { | |
return mortgage; | |
} | |
/** | |
* @param mortgage the mortgage to set | |
*/ | |
public void setMortgage(String mortgage) { | |
this.mortgage = mortgage; | |
} | |
/** | |
* @return the pep | |
*/ | |
public String getPep() { | |
return pep; | |
} | |
/** | |
* @param pep the pep to set | |
*/ | |
public void setPep(String pep) { | |
this.pep = pep; | |
} | |
} |
public abstract class Client { | |
public abstract void readData(); //read file detail | |
public abstract void processData(); //process file detail | |
public abstract void printData(); //print file detail | |
} |