Java中的Lambda简析笔记
参考资料
- 《Java编程思想(第四版)》
- Java学习网站:How2java.cn
- 大佬博客:Java中的Lambda
介绍Lambda,首先应从普通方法,匿名类以及Lambda方式的比较中清晰为什么要有Lambda,见如下题目:
例题:找出满足条件的Hero对象,如下:
初始化后的集合: [Hero [name=hero 0,hp=77.0,damage=28] ,Hero [name=hero 1,hp=984.0,damage=89] ,Hero [name=hero 2,hp=350.0,damage=19] ,Hero [name=hero 3,hp=731.0,damage=41] ,Hero [name=hero 4,hp=489.0,damage=33] ] 筛选出 hp>100 && damange<50的英雄 Hero [name=hero 2,hp=350.0 damage=19] Hero [name=hero 3,hp=731.0 damage=41] Hero [name=hero 4,hp=489.0 damage=33]
public class Hero implements Comparable<Hero>{
public String name;
public float hp;
public int damage;
public Hero(){
}
public Hero(String name) {
this.name =name;
}
//初始化name,hp,damage的构造方法
public Hero(String name,float hp, int damage) {
this.name =name;
this.hp = hp;
this.damage = damage;
}
@Override
public int compareTo(Hero anotherHero) {
if(damage<anotherHero.damage)
return 1;
else
return -1;
}
@Override
public String toString() {
return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
}
}
一、筛选数据的方法
筛选方法1:普通方法
- 实现filter()方法,对hero列表进行遍历检查。
public void filter(List<Hero> heros){
for(Hero hero:heros){
if(hero.hp>100 && hero.damage<50)
System.out.println(hero);
}
}
筛选方法2:匿名类方法
-
利用匿名类HeroChecker检查hero是否符合要求,符合要求则输出
public interface HeroChecker{ public boolean test(Hero h); }
-
在类中具体实现匿名类接口,检查hero
public HeroChecker checker = new HeroChecker(){ @Override public boolean test(Hero h){ return (h.hp>100 && h.damage<50); } }
-
在filter()函数中实现hero的遍历检查
public static void filter(List<Hero> heros,HeroChecker checker){ for(Hero h:heros){ if(checker.test(h)){ System.out.println(h); } } }
筛选方法3:Lambda方式
题外:Lambda是由匿名类一点一点演变过来的
Lambda语法
基本的语法:
- (parameters)->expression
- (parameters)->{statements;}
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
二、设置排序集合方式
//先做一个字符串数组strs
String[] strs = {"LPB","ZXF","BYD","ZZY",
"CHL","PKF","HHB","HY"};
2.1、使用匿名内部类排序
Arrays.sort(strs,new Comparator<String>(){
@Override
public int compare(String s1,String s2){
return s1.compareTo(s2);
}
});
2.2、使用Lambda排序集合
//lambda expression排序strs
Compare<String> sortByName = (String s1,String s2)->
s1.compareTo(s2);
//省略,一行排序
Arrays.sort(strs,(String s1,String s2)->
s1.compareTo(s2));
三、Lambdas和Streams的合作
Streams是对集合的包装,常与lambda一起使用;使用lambda可支持许多的操作如map、filter、limit、sorted、count、collect等等。
Streams使用懒运算,其并不会真正读取到数据,遇到如getFirst()如此的方法便会结束链式语法。
注:Streams操作也可以设为并行的,将stream()换为parallelStream()即可。
实体类Person:
public class Person{
private String firstName,lastName,job,gender;
private int salary,age;
public Person(String firstName,String lastName,
String job,String gender,int salary,
int age){
this.firstName = firstName;
this.lastName = lastName;
this.job = job;
this.gender = gender;
this.salary = salary;
this.age = age;
}
//省略get方法以及set方法
}
我们先实现两个数组,分别表示Java程序员和C++程序员
List<Person> javaProgrammers = new ArrayList<Person>() {
{
add(new Person("Elsdon", "Jaycob", "Javaprogrammer", "male", 43, 2000));
add(new Person("Tamsen", "Brittany", "Javaprogrammer", "female", 23, 1500));
add(new Person("Floyd", "Donny", "Javaprogrammer", "male", 33, 1800));
add(new Person("Sindy", "Jonie", "Javaprogrammer", "female", 32, 1600));
add(new Person("Vere", "Hervey", "Javaprogrammer", "male", 22, 1200));
add(new Person("Maude", "Jaimie", "Javaprogrammer", "female", 27, 1900));
add(new Person("Shawn", "Randall", "Javaprogrammer", "male", 30, 2300));
add(new Person("Jayden", "Corrina", "Javaprogrammer", "female", 35, 1700));
add(new Person("Palmer", "Dene", "Javaprogrammer", "male", 33, 2000));
add(new Person("Addison", "Pam", "Javaprogrammer", "female", 34, 1300));
}
};
List<Person> cppProgrammers = new ArrayList<Person>() {
{
add(new Person("Jarrod", "Pace", "Cppprogrammer", "male", 34, 1550));
add(new Person("Clarette", "Cicely", "Cppprogrammer", "female", 23, 1200));
add(new Person("Victor", "Channing", "Cppprogrammer", "male", 32, 1600));
add(new Person("Tori", "Sheryl", "Cppprogrammer", "female", 21, 1000));
add(new Person("Osborne", "Shad", "Cppprogrammer", "male", 32, 1100));
add(new Person("Rosalind", "Layla", "Cppprogrammer", "female", 25, 1300));
add(new Person("Fraser", "Hewie", "Cppprogrammer", "male", 36, 1100));
add(new Person("Quinn", "Tamara", "Cppprogrammer", "female", 21, 1000));
add(new Person("Alvin", "Lance", "Cppprogrammer", "male", 38, 1600));
add(new Person("Evonne", "Shari", "Cppprogrammer", "female", 40, 1800));
}
};
3.1、forEach迭代
- 迭代输出列表
javaProgrammers.forEach((p) -> System.out.printf("%s,%s;",
p.getFirstName,p.getLastName()));
cppProgramers.forEach((p) -> System.out.printf("%s,%s;",
p.getFirstName(),p.getLastName()));
- 给所有程序员加薪,增加50%工资
Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 2
+ e.getSalary());
javaProgrammers.forEach(giveRaise);
phpProgrammers.forEach(giveRaise);
3.2、过滤器filter()
- 使用过滤器显示集合中符合特定条件的对象
//显示月薪超过1000美元的Java程序员
javaProgrammers.stream()
.filter((p)->(p.getSalary()>1000))
.forEach((p)->System.out.printf("%s,%s;",p.getFirstName(),p.getLastName()));
- 此外还可以定义过滤器,通过重用过滤器来执行其他的操作
Predicate<Person> ageFilter = (p)->(p.getAge()>25);
Predicate<Person> salaryFilter = (p)->(p.getSalary()>1000);
Predicate<Person> genderFilter = (p)->("female".equals(p.getGender()));
//输出年龄大于25、月薪在1000以上的女cpp程序员
cppProgrammers.stream()
.filter(ageFilter)
.filter(salaryFilter)
.filter(genderFilter)
.forEach((p)->System.out.printf("%s,%s;",p.getFirstName(),p.getLastName()));
//输出年龄大于25、月薪在1000以上的女java程序员
javaProgrammers.stream()
.filter(ageFilter)
.filter(salaryFilter)
.filter(genderFilter)
.forEach((p)->System.out.printf("%s,%s;",p.getFirstName(),p.getLastName()));
使用 limit(int n); 函数可以实现是输出前 n 个对象元素;
另外我们在stream中同样可以使用 sorted()实现排序:
//根据name排序,并输出前5个Java程序员 List<Person> sortedJavaProgrammers = javaProgrammers.stream() .sorted((p1,p2)->(p.getFirstName().compareTo(p2.getFirstName()))) .limit(5) .collect(toList()); sortedJavaProgrammers.forEach((p)->System.out.printf( "%s %s,%n",p.getFirstName(),p,getLastName()));
3.3、min、max方法
当然,我们可以通过过滤器filter()只过滤出最小或最大的值,但速度肯定是比直接用min或max方法慢的
//输出工资最低的 Java 程序员
Person pers = javaProgrammers
.stream()
.min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
.get()
System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())
//输出工资最高的 Java 程序员
Person person = javaProgrammers
.stream()
.max((p, p2) -> (p.getSalary() - p2.getSalary()))
.get()
System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())
3.4、利用map和collect方法存放结果集
我们可以将map()和 collect()结合,将结果集存放到一个字符串、Set或TreeSet中:
//将 cpp程序员 的 first name 拼接成字符串
String phpDevelopers = phpProgrammers
.stream()
.map(Person::getFirstName)
.collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token)
//将 Java程序员 的 first name 存放到 Set
Set<String> javaDevFirstName = javaProgrammers
.stream()
.map(Person::getFirstName)
.collect(toSet());
//将 Java程序员 的 first name 存放到 TreeSet
TreeSet<String> javaDevLastName = javaProgrammers
.stream()
.map(Person::getLastName)
.collect(toCollection(TreeSet::new));