Lambda表达式
五、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表达式是可以在函数式接口上使用的。函数式接口就是只定义一个抽象方法的接口。比如:
public interface Predicate<T>{
boolean test (T t);
}
public interface Comparator<T>(){
int compare(T o1,T o2);
}
public interface Runnable{
void run();
}
其实,Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例(确切来说,是函数式接口的一个具体实现的实例)。
public static String processFile() throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))){
return br.readLine();
}
}
如果我们想要从一个文件中读取一行所需的内容,可以定义这样的方法:
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。
java.util.function.Predicate<T>接口定义了一个名叫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);
java.util.function.Consumer<T>接口定义了一个名叫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)
);
java.util.function.Function<T, R>接口定义了一个叫作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()
);
java.util.function.Supplier<T>接口定义了一个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