学习目标:
学会使用Lambda表达式及其相关操作
学习内容:
一.什么是Lambda表达式?
1.概念:
Lambda表达式,也可以成为闭包。是Java 8的一个重要新特性。
与匿名类相比,就是匿名方法,是一种把方法作为参数进行传递的编程思想。
2.使用示例:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//参考文章末尾的英雄类
import charactor.Hero;
public class TestLamdba {
public static void main(String[] args) {
Random r = new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
System.out.println("初始化后的集合:");
System.out.println(heros);
System.out.println("使用匿名类的方式,筛选出 hp>100 && damange<50的英雄");
// 匿名类的正常写法
HeroChecker c1 = new HeroChecker() {
@Override
public boolean test(Hero h) {
return (h.hp > 100 && h.damage < 50);
}
};
// 把new HeroChcekcer,方法名,方法返回类型信息去掉
// 只保留方法参数和方法体
// 参数和方法体之间加上符号 ->
HeroChecker c2 = (Hero h) -> {
return h.hp > 100 && h.damage < 50;
};
// 把return和{}去掉
HeroChecker c3 = (Hero h) -> h.hp > 100 && h.damage < 50;
// 把 参数类型和圆括号去掉
HeroChecker c4 = h -> h.hp > 100 && h.damage < 50;
// 把c4作为参数传递进去
filter(heros, c4);
// 直接把表达式传递进去
filter(heros, h -> h.hp > 100 && h.damage < 50);
}
private static void filter(List<Hero> heros, HeroChecker checker) {
for (Hero hero : heros) {
if (checker.test(hero))
System.out.print(hero);
}
}
}
3.lambda表达式的重要特征:
(1)可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
(2)可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
(3)可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
(4)可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
4.使用Lambda表达式的好处:
(1)使代码更简洁
(2)可以装逼
5.不好的地方:
Lambda比较适合用在简短的业务代码中,并不适合用在复杂的系统中,会加大维护成本。
(1) 可读性差:与啰嗦的但是清晰的匿名类代码结构比较起来,Lambda表达式一旦变得比较长,就难以理解
(2) 不便于调试:很难在Lambda表达式中增加调试信息,比如日志
(3) 版本支持:Lambda表达式在JDK8版本中才开始支持,如果系统使用的是以前的版本,考虑系统的稳定性等原因,而不愿意升级,那么就无法使用。
二.方法引用
1.引用静态方法:
import java.util.*;
//参考文章末尾的英雄类
import charactor.Hero;
//lambda表达式引用静态方法
public class test3 {
public static void main(String[] args) {
Random r =new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 10; i++) {
//通过随机值实例化hero的hp和damage
heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
}
//Comparator<Hero> c = new
//lambda表达式引用静态方法
Collections.sort(heros,test3::maxMin);
System.out.println("按照血量排序后的集合:");
System.out.println(heros);
}
public static int maxMin(Hero h1,Hero h2){
if(h1.hp>=h2.hp)
return 1;
else
return -1;
}
}
2.引用对象方法:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
//参考文章末尾的英雄类
import charactor.Hero;
//lambda表达式引用对象方法
public class test4 {
public static void main(String[] args) {
Random r =new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 10; i++) {
//通过随机值实例化hero的hp和damage
heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
}
//Comparator<Hero> c = new
//lambda表达式引用对象方法
test4 t4 = new test4();
Collections.sort(heros,t4::maxMin);
System.out.println("按照血量排序后的集合:");
System.out.println(heros);
}
public int maxMin(Hero h1,Hero h2){
if(h1.hp>=h2.hp)
return 1;
else
return -1;
}
}
3.引用构造器:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;
//参考文章末尾的英雄类
import charactor.Hero;
//lambda表达式引用构造器
public class test6 {
public static void main(String[] args) {
List<Integer> l;
l = new ArrayList<>();
modify(l, "ArrayList");
l = new LinkedList<>();
modify(l, "LinkedList");
//lambda表达式引用构造器
List list1 = getList(ArrayList::new);
modify(list1, "ArrayList");
}
public static List getList(Supplier<List> s) {
return s.get();
}
private static void modify(List<Integer> l, String type) {
int total = 100 * 1000;
int index = total / 2;
final int number = 5;
//初始化
for (int i = 0; i < total; i++) {
l.add(number);
}
long start = System.currentTimeMillis();
for (int i = 0; i < total; i++) {
int n = l.get(index);
n++;
l.set(index, n);
}
long end = System.currentTimeMillis();
System.out.printf("%s总长度是%d,定位到第%d个数据,取出来,加1,再放回去%n 重复%d遍,总共耗时 %d 毫秒 %n", type, total, index, total, end - start);
System.out.println();
}
}
三.聚合操作
一.概念:
要了解聚合操作,首先要建立 Stream 和 管道 的概念
*Stream 和Collection结构化的数据不一样,Stream是一系列的元素,就像是生产线上的罐头一样,一串串的出来。
*管道指的是一系列的聚合操作。
管道又分3个部分
*管道源:Collection切换成管道源很简单,调用stream()就行了。数组没有stream()方法,需要使用Arrays.stream(arr) //arr是数组名
*中间操作: 每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。
中间操作比较多,主要分两类
对元素进行筛选:
filter 匹配
distinct 去除重复(根据equals判断)
sorted 自然排序
sorted(Comparator) 指定排序
limit 保留
skip 忽略
转换为其他形式的流
mapToDouble 转换为double的流
map 转换为任意类型的流
*结束操作:当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回, 结束操作才进行真正的遍历行为,在遍历的时候,才会去进行中间操作的相关判断。
常见结束操作如下:
forEach() 遍历每个元素
toArray() 转换为数组
min(Comparator) 取最小的元素
max(Comparator) 取最大的元素
count() 总数
findFirst() 第一个元素
注: 这个Stream和I/O章节的InputStream,OutputStream是不一样的概念。
二.使用示例:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//参考文章末尾的英雄类
import charactor.Hero;
/*
首选准备10个Hero对象,hp和damage都是随机数。
分别用传统方式和聚合操作的方式,把hp第三高的英雄名称打印出来
*/
public class test7 {
public static void main(String[] args) {
Random random = new Random();
List<Hero> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Hero h = new Hero();
h.name = "hero"+i;
h.hp = random.nextInt(100);
h.damage = random.nextInt(500);
list.add(h);
}
/**
* 我写的
//聚合遍历集合
list
.stream()
.forEach(h -> System.out.println(h));
//System.out.println(list);
//聚合排序
Object[] heroes = list.stream().sorted((h1, h2)->h1.hp>h2.hp?1:-1).toArray();
System.out.println(heroes[heroes.length-3]);
我是个渣渣!*/
//别人写的的
String name =list
.stream()
.sorted((h1,h2)->h1.hp>h2.hp?-1:1)
.skip(2)
.map(h->h.getName())
.findFirst()
.get();
System.out.println(name);
}
}
学习时间:
三小时
继续奋斗!
另:英雄类
public class Hero{
public String name;
public float hp;
public int damage;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getHp() {
return hp;
}
public void setHp(float hp) {
this.hp = hp;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public Hero(){
}
public Hero(String name) {
this.name =name;
}
public boolean matched(){
return this.hp>100 && this.damage<50;
}
public Hero(String name,float hp, int damage) {
this.name =name;
this.hp = hp;
this.damage = damage;
}
public int compareHero(Hero h){
return hp>=h.hp?-1:1;
}
public String toString() {
return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
}
}