五、Lambdad表达式综合案例:
废话不多说,上代码(讲解在代码注释中):
5.1、集合排序
package com.zhangshangbiancheng.exercise; import com.zhangshangbiancheng.data.Person; import java.util.ArrayList; import java.util.Comparator; public class Exercise1 { //集合排序 //ArrayList<> public static void main(String[] args) { //需求:已知在一个ArrayList中有若干个Person对象,将这些Person对象按照年龄降序排列 ArrayList<Person> list = new ArrayList<>(); list.add(new Person("掌上编程1",1)); list.add(new Person("掌上编程2",12)); list.add(new Person("掌上编程3",13)); list.add(new Person("掌上编程4",24)); list.add(new Person("掌上编程5",56)); list.add(new Person("掌上编程6",65)); list.add(new Person("掌上编程7",43)); list.add(new Person("掌上编程8",34)); list.sort((o1,o2) ->o2.age-o1.age); //list.sort(Comparator.comparing()); int compare(T o1, T o2); System.out.println(list); } }
5.2、TreeSet:
package com.zhangshangbiancheng.exercise; import com.zhangshangbiancheng.data.Person; import java.util.TreeSet; public class Exercise2 { public static void main(String[] args) { //TreeSet //无参数创建会报错 java.lang.ClassCastException: com.zhangshangbiancheng.data.Person cannot be cast to java.lang.Comparable //修改 :使用Lambda表达式来实现Comparator接口,并实例化一个TreeSet对象 TreeSet<Person> set = new TreeSet<>((o1, o2) -> o2.age-o1.age); //若为为要同元素 则之显示出一个 比较为零做处理避免此情况发生 TreeSet<Person> set = new TreeSet<>((o1, o2) -> { if (o1.age >= o2.age){ return -1; } else { return 1; } }); set.add(new Person("掌上编程1",1)); set.add(new Person("掌上编程2",12)); set.add(new Person("掌上编程3",13)); set.add(new Person("掌上编程4",24)); set.add(new Person("掌上编程5",56)); set.add(new Person("掌上编程6",65)); set.add(new Person("掌上编程7",43)); set.add(new Person("掌上编程8",34)); set.add(new Person("掌上编程9",12)); System.out.println(set); } }
5.3、集合的遍历:
package com.zhangshangbiancheng.exercise; import com.zhangshangbiancheng.data.Person; import java.util.ArrayList; import java.util.Collections; public class Exercise3 { public static void main(String[] args) { //集合的和遍历 ArrayList<Integer> list = new ArrayList<>(); Collections.addAll(list, 1, 2, 3, 4); //将集合中每一个元素都带入到方法accept中 void accept(T t); list.forEach(System.out::println); //输出集合中所有的偶数 list.forEach(ele -> { if (ele % 2 == 0){ System.out.println(ele); } }); } }
5.4、删除集合中元素:
package com.zhangshangbiancheng.exercise; import com.zhangshangbiancheng.data.Person; import java.util.ArrayList; import java.util.Iterator; public class Exericse4 { public static void main(String[] args) { //需求:删除集合中的元素 ArrayList<Person> list = new ArrayList<>(); list.add(new Person("掌上编程1",1)); list.add(new Person("掌上编程2",12)); list.add(new Person("掌上编程3",13)); list.add(new Person("掌上编程4",24)); list.add(new Person("掌上编程5",56)); list.add(new Person("掌上编程6",65)); list.add(new Person("掌上编程7",43)); list.add(new Person("掌上编程8",34)); //删除几何中年龄>10岁的元素 迭代器 Iterator<Person> it = list.iterator(); while (it.hasNext()){ Person ele = it.next(); if (ele.age>10){ it.remove(); } System.out.println(list); } //Lambda实现 //将集合 list.removeIf(ele ->ele.age>10); } }
5.5、线程相关:
package com.zhangshangbiancheng.exercise; public class Exericse5 { public static void main(String[] args) { Thread t = new Thread(() -> { for (int i = 0;i<100;i++){ System.out.println(i); } }); t.run(); } // }
六、闭包
package com.zhangshangbiancheng.closure; import java.util.function.Supplier; public class ClosureDemo { public static void main(String[] args) { //闭包 提升变量的生命周期 int n = getNumber().get(); System.out.println(n); } private static Supplier<Integer> getNumber(){ int num = 10; return ()->{ return num; }; } }
package com.zhangshangbiancheng.closure; import java.util.function.Consumer; public class ClosureDemo2 { public static void main(String[] args) { //此时a 是final 运行时默认添加 一定是常量 int a = 10; Consumer<Integer> c = ele->{ System.out.println(a); }; c.accept(a); } }
总结:
什么时候可以使用Lambda
Lambda表达式是可以在函数式接口上使用的。函数式接口就是只定义一个抽象方法的接口。比如:
public interface Predicate<T>{ boolean test (T t); } public interface Comparator<T>(){ int compare(T o1,T o2); } public interface Runnable{ void run(); }
其实,Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例(确切来说,是函数式接口的一个具体实现的实例)。
Lambda表达式的具体使用
如果我们想要从一个文件中读取一行所需的内容,可以定义这样的方法:
public static String processFile() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))){ return br.readLine(); } }
Lambda表达式的具体使用
如果我们想要从一个文件中读取一行所需的内容,可以定义这样的方法:
public static String processFile() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))){ return br.readLine(); } }
那如果要读取两行呢,这时候我们就应该记起来行为参数化。
使用函数式接口来传递行为
public static String processFile(BufferedReaderProcessor p) throws Exception{ try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))){ return p.process(br); } }
传递Lambda
现在我们就可以通过传递不同的Lambda重用processFile方法,以不同方式处理文件。
处理一行:
String oneLine = processFile((BufferedReader br) -> br.readLine());
处理两行:
String twoLine = processFile((BufferedReader br) -> br.readLine() + br.readLine());
几种函数式接口
Java 8中常用的函数式接口有三个:Predicate,Consumer,Function。
Predicate
java.util.function.Predicate接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。在需要表示一个涉及类型T的布尔表达式时,可以使用这个接口。比如,你可以定义一个接受String对象的Lambda表达式。
@FunctionalInterface public interface Predicate<T> { boolean test(T t); } public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> results = new ArrayList<>(); for(T s: list){ if(p.test(s)){ results.add(s); } } return results; } Predicate<String> predicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, predicate);
Consumer
java.util.function.Consumer接口定义了一个名叫accept的抽象方法,它接受泛型T,没有返回值(void)。如果需要访问类型T的对象,并对其执行某些操作,可以使用这个接口。
比如定义一个forEach方法,接受一个Integer类型的列表,并对每个元素执行打印操作。
@FunctionalInterface public interface Consumer<T> { void accept(T t); } public static <T> void forEach(List<T> list,Consumer<T> c) { for(T i: list) { c.accept(i); } } forEach( Arrays.asList(1,2,3,4,5),(Integer i) -> System.out.println(i) );
Function
java.util.function.Function接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。如果需要定义一个Lambda,将输入的信息映射到输出,可以使用这个接口(比如提取苹果的重量,或把字符串映射为它的长度)。
比如,定义一个map方法,将一个String列表映射到包含每个String长度的Integer列表。
@FunctionalInterface public interface Function<T, R>{ R apply(T t); } public static <T, R> List<R> map(List<T> list, Function<T, R> f) { List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } // [6,3,6] List<Integer> list = map( Arrays.asList("lambda","int","action"), (String s) -> s.length() );
Supplier
java.util.function.Supplier接口定义了一个get的抽象方法,它没有参数,返回一个泛型T的对象,这类似于一个工厂方法。
比如返回一个Apple对象。
public interface Supplier<T> { T get(); } public static <T> T getObject(Supplier<T> s) { return s.get(); } Apple apple = getObject(() -> new Apple());
package com.zhangshangbiancheng.functional; import java.util.function.*; public class FunctionInterface { public static void main(String[] args) { //系统内部的函数式接口 //Predicate<T> 参数T 返回值boolean //IntPredicate int->boolean //LongPredicate long->boolean //DoublePredicate double->boolean //Consumer<T> 参数T 返回值void //IntConsumer int->boolean //LongConsumer long->void //DoubleConsumer double->void //Function<T,R> 参数T 返回值R 指定类型参数 指定类型返回值 //IntFunction<R> int->R //LongFunction<R> long->R //DoubleFunction<R> double->R //IntToLongFunction int->long //LongToIntFunction long->int //LongToDoubleFunction long->double //DoubleToIntFunction double->int //DoubleToLongFunction double->long //Supplier<T> 参数无 返回值T //UnaryOperator<T> 参数T 返回值T //BinaryOperator<T> 参数T,T 返回值T 继承 BiFunction<T,U,R> //BiFunction<T,U,R> 参数T,U 返回值R //BiPredicate<T,U> 参数T,U 返回值boolean //BiConsumer<T,U> 参数T,U 返回值void //比较常用的函数式接口 Predicte<T> Consumer<T> Function<T,R> Supplier<T> 其他只是补充 } }
在了解了Lambda表达式的和方法引用的用法之后,你就可以自己去尝试用Lambda表达式去简化一些代码了(你可以自己去练习一下)。不过用于传递Lambda表达式的Comparator、Function、Predicate等函数式接口提供了允许你进行复合的方法。这意味着你可以把多个简单的Lambda复合成复杂的表达式。有兴趣的童鞋可以自己去了解下,这里不再详细讲解。项目地址:
https://github.com/Mazongdiulejinguzhou/Mazongdiulejinguzhou.github.io/tree/develop-Lambda-test
devlop-Lambda-test分支