本文共 7792 字,大约阅读时间需要 25 分钟。
学会使用Lambda表达式及其相关操作
Lambda表达式,也可以成为闭包。是Java 8的一个重要新特性。
与匿名类相比,就是匿名方法,是一种把方法作为参数进行传递的编程思想。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(); Listheros = 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 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 heros, HeroChecker checker) { for (Hero hero : heros) { if (checker.test(hero)) System.out.print(hero); } } }
(1)可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
(2)可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
(3)可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
(4)可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
(1)使代码更简洁
(2)可以装逼Lambda比较适合用在简短的业务代码中,并不适合用在复杂的系统中,会加大维护成本。
(1) 可读性差:与啰嗦的但是清晰的匿名类代码结构比较起来,Lambda表达式一旦变得比较长,就难以理解
(2) 不便于调试:很难在Lambda表达式中增加调试信息,比如日志
(3) 版本支持:Lambda表达式在JDK8版本中才开始支持,如果系统使用的是以前的版本,考虑系统的稳定性等原因,而不愿意升级,那么就无法使用。
import java.util.*;//参考文章末尾的英雄类import charactor.Hero;//lambda表达式引用静态方法public class test3 { public static void main(String[] args) { Random r =new Random(); Listheros = new ArrayList (); for (int i = 0; i < 10; i++) { //通过随机值实例化hero的hp和damage heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100))); } //Comparator 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; }}
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(); Listheros = new ArrayList (); for (int i = 0; i < 10; i++) { //通过随机值实例化hero的hp和damage heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100))); } //Comparator 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; }}
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) { Listl; 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 s) { return s.get(); } private static void modify(List
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(); Listlist = 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"; }}
转载地址:http://xdozi.baihongyu.com/