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";
}
}
// 测试类
public class TestLambda {
public static void main(String[] args) {
Random r = new Random();
List heros = new ArrayList();
for (int i = 0; i < 10; 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的英雄");
filter(heros);
}
// 找出血量>100 和 伤害值小于50
private static void filter(List heros) {
for (Hero hero : heros) {
if(hero.hp>100 && hero.damage<50)
System.out.print(hero);
}
}
}
定义接口
import charactor.Hero;
public interface HeroChecker {
public boolean test(Hero h);
}
测试类
public class TestLambda {
public static void main(String[] args) {
Random r = new Random();
List heros = new ArrayList();
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 checker = new HeroChecker() {
@Override
public boolean test(Hero h) {
return (h.hp>100 && h.damage<50);
}
};
filter(heros,checker);
}
private static void filter(List heros,HeroChecker checker) {
for (Hero hero : heros) {
if(checker.test(hero))
System.out.print(hero);
}
}
}
使用Lambda方式筛选出数据
filter(heros,(h)->h.hp>100 && h.damage<50);
Lambda表达式可以看成是匿名类一点点演变过来
1、匿名类的正常写法
HeroChecker c1 = new HeroChecker() {
public boolean test(Hero h) {
return (h.hp>100 && h.damage<50);
}
};
2、把外面的壳子去掉
只保留方法参数和方法体
参数和方法体之间加上符号 ->
HeroChecker c2 = (Hero h) ->{
return h.hp>100 && h.damage<50;
};
3、把return和{}去掉
HeroChecker c3 = (Hero h) ->h.hp>100 && h.damage<50;
4、把 参数类型和圆括号去掉(只有一个参数的时候,才可以去掉圆括号)
HeroChecker c4 = h ->h.hp>100 && h.damage<50;
5、 把c4作为参数传递进去
filter(heros,c4);
6、直接把表达式传递进去
filter(heros, h -> h.hp > 100 && h.damage < 50);
与匿名类 概念相比较,
Lambda 其实就是匿名方法,这是一种把方法作为参数进行传递的编程思想。
虽然代码是这么写
filter(heros, h -> h.hp > 100 && h.damage < 50);
但是,Java会在背后,悄悄的,把这些都还原成。引入Lambda表达式,会使得代码更加紧凑,而不是各种接口和匿名类到处飞。
Lambda表达式虽然带来了代码的简洁,但是也有其局限性。
Lambda比较适合用在简短的业务代码中,并不适合用在复杂的系统中,会加大维护成本。
首先为TestLambda添加一个静态方法:
public static boolean testHero(Hero h) {
return h.hp>100 && h.damage<50;
}
Lambda表达式:
filter(heros, h->h.hp>100 && h.damage<50);
lambda表达式调用这个静态方法
filter(heros, h->TestLambda.testHero(h));
调用静态方法改写
filter(heros, TestLambda::testHero);
与引用静态方法很类似,只是传递方法的时候,需要一个对象的存在
TestLambda testLambda= new TestLambda();
filter(heros, testLambda::testHero));
3、引用容器中的对象
首先为Hero添加一个方法
public boolean patch(){
return this.hp>100 && this.damage<50;
}
在lambda表达式中调用容器中的对象Hero的方法
filter(heors, h-> h.patch());
patch恰好就是容器中的对象Hero的方法,那就可以进一步改写为
filter(heros, Hero::patch);
有的接口中的方法会返回一个对象,比如java.util.function.Supplier提供
了一个get方法,返回一个对象
public interface Supplier {
T get();
}
设计一个方法,参数是这个接口
public static List getList(Supplier s){
return s.get();
}
为了调用这个方法,有3种方式
第一种匿名类:
Supplier s = new Supplier(){
public List get(){
return new ArrayList(); }
};
第二种Lambda表达式
Supplier s = getList(()->new ArrayList());
第三种引用构造器
SUppliser s = getList(ArrayList:: new );
for循环遍历
for (Hero h : heros) {
if (h.hp > 100 && h.damage < 50)
System.out.println(h.name);
}
聚合操作遍历
heros
.stream()
.filter(h.hp > 100 && h.damage < 50)
.forEach(h -> System.out.println(h.name));
heros
.stream()
.filter(h.hp > 100 && h.damage < 50)
.forEach(h -> System.out.println(h.name));
要了解聚合操作,首先要建立Stream和管道的概念
Stream 和Collection结构化的数据不一样,Stream是一系列的元素,就像是生产线上的罐头一样,一串串的出来。
管道指的是一系列的聚合操作。
管道又分3个部分
把Collection切换成管道源很简单,调用stream()就行了。
heros.stream();
但是数组却没有stream()方法,需要使用
Arrays.stream(heros);
或者
Stream.of(heros);
每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。
中间操作比较多,主要分两类
对元素进行筛选 和 转换为其他形式的流
对元素进行筛选:
filter 匹配
distinct 去除重复(根据equals判断)
sorted 自然排序
sorted(Comparator) 指定排序
limit 保留
skip 忽略
转换为其他形式的流
mapToDouble 转换为double的流
map 转换为任意类型的流
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import charactor.Hero;
public class TestAggregate {
public static void main(String[] args) {
Random r = new Random();
List heros = new ArrayList();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
//制造一个重复数据
heros.add(heros.get(0));
System.out.println("初始化集合后的数据 (最后一个数据重复):");
System.out.println(heros);
System.out.println("满足条件hp>100&&damage<50的数据");
heros
.stream()
.filter(h->h.hp>100&&h.damage<50)
.forEach(h->System.out.print(h));
System.out.println("去除重复的数据,去除标准是看equals");
heros
.stream()
.distinct()
.forEach(h->System.out.print(h));
System.out.println("按照血量排序");
heros
.stream()
.sorted((h1,h2)->h1.hp>=h2.hp?1:-1)
.forEach(h->System.out.print(h));
System.out.println("保留3个");
heros
.stream()
.limit(3)
.forEach(h->System.out.print(h));
System.out.println("忽略前3个");
heros
.stream()
.skip(3)
.forEach(h->System.out.print(h));
System.out.println("转换为double的Stream");
heros
.stream()
.mapToDouble(Hero::getHp)
.forEach(h->System.out.println(h));
System.out.println("转换任意类型的Stream");
heros
.stream()
.map((h)-> h.name + " - " + h.hp + " - " + h.damage)
.forEach(h->System.out.println(h));
}
}
当进行结束操作后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回,。
结束操作才真正进行遍历行为,前面的中间操作也在这个时候,才真正的执行。
常见结束操作如下:
forEach() 遍历每个元素
toArray() 转换为数组
min(Comparator) 取最小的元素
max(Comparator) 取最大的元素
count() 总数
findFirst() 第一个元素
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
import charactor.Hero;
public class TestAggregate {
public static void main(String[] args) {
Random r = new Random();
List heros = new ArrayList();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
System.out.println("遍历集合中的每个数据");
heros
.stream()
.forEach(h->System.out.print(h));
System.out.println("返回一个数组");
Object[] hs= heros
.stream()
.toArray();
System.out.println(Arrays.toString(hs));
System.out.println("返回伤害最低的那个英雄");
Hero minDamageHero =
heros
.stream()
.min((h1,h2)->h1.damage-h2.damage)
.get();
System.out.print(minDamageHero);
System.out.println("返回伤害最高的那个英雄");
Hero mxnDamageHero =
heros
.stream()
.max((h1,h2)->h1.damage-h2.damage)
.get();
System.out.print(mxnDamageHero);
System.out.println("流中数据的总数");
long count = heros
.stream()
.count();
System.out.println(count);
System.out.println("第一个英雄");
Hero firstHero =
heros
.stream()
.findFirst()
.get();
System.out.println(firstHero);
}
}
注意: 我尝试了代码一旦结束了聚合,也就是流用光了,数据有回复原来的样子 聚合方式操作集合不是永久性的 ,那么用聚合整理出来的集合就无法用来进行下面的操作,这怎么处理 --> 整理出来的集合, 应该用一个新的集合来接.
List list=heros ``.stream() ``.sorted((h1,h2) -> h1.damage>h2.damage?``1``:-``1``) ``.collect(Collectors.toList());
大部分内容代码来源:来源how2j.cn网站