读书笔记——《Java 8实战》系列之Lambda表达式(二)
2017-10-31 12:04
651 查看
转自 http://www.wxueyuan.com/blog/articles/2017/10/16/1508115706213.html
在上一篇博客中,我们介绍了Lambda表达式的基本概念以及语法。在本片博客中,我们将继续和大家分享一些关于Lambda表达式的知识。
函数式接口只定义了一个抽象方法,该抽象方法的签名也被称为函数描述符。为了应用不同的Lambda表达式,Java 的库设计师们提供了一些常用的函数式接口,比如我们之前接触到的Comparable,Runnable和Callable。Java 8在此基础上,又增加了几个新的函数接口,接下来我们就一起来了解它们一下。
java.util.function.Predicate
Predicate接口定义了一个名叫test的抽象方法,他接受泛型T的对象,并返回一个Boolean值。看过本系列读书笔记的同学们是不是觉得很眼熟?没错,它和我们在行为参数化博客中自己创建的函数式接口一模一样。当我们需要使用一个传入对象并返回布尔值的表达式时,直接使用它吧。
java.util.function.Consumer
Consumer定义了一个accept抽象方法。它接受泛型类型对象T,并没有返回任何值。如果我们需要访问T类型的对象,并对其执行某些操作,我们就可以使用这个接口了
java.util.function.Function
接下来我们来一起总结一些常用的Lambda的例子以及可以使用的函数式接口。
迄今为止,我们所介绍的所有Lambda表达式都只用到了其主体中的参数,如使用了学生实例的身高属性
但实际上Lambda表达式也允许我们使用自由变量(不允许当作参数,可以在主体中使用外层作用域中定义的变量),如:
Lambda表达式同样能够在主体中使用实例变量和静态变量。但是局部变量必须显式声明为final或事实上为final,换句话说,Lambda表达式主体中使用过的局部变量,不能被再次赋值。
错误示范:
在上一篇博客中,我们介绍了Lambda表达式的基本概念以及语法。在本片博客中,我们将继续和大家分享一些关于Lambda表达式的知识。
函数式接口只定义了一个抽象方法,该抽象方法的签名也被称为函数描述符。为了应用不同的Lambda表达式,Java 的库设计师们提供了一些常用的函数式接口,比如我们之前接触到的Comparable,Runnable和Callable。Java 8在此基础上,又增加了几个新的函数接口,接下来我们就一起来了解它们一下。
java.util.function.Predicate
Predicate接口定义了一个名叫test的抽象方法,他接受泛型T的对象,并返回一个Boolean值。看过本系列读书笔记的同学们是不是觉得很眼熟?没错,它和我们在行为参数化博客中自己创建的函数式接口一模一样。当我们需要使用一个传入对象并返回布尔值的表达式时,直接使用它吧。
@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> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
java.util.function.Consumer
Consumer定义了一个accept抽象方法。它接受泛型类型对象T,并没有返回任何值。如果我们需要访问T类型的对象,并对其执行某些操作,我们就可以使用这个接口了
@FunctionalInterface public interface Consumer<T>{ void accept(T t); } public static <T> void forEach(List<T> list, Consumer<T> c){ for(T t:list){ c.accept(t); } } forEach(Arrays.asList( b6af 1,2,3,4,5), (Integer i)-> System.out.println(i));
java.util.function.Function
@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<R>(); for(T t: list){ result.add(f.apply(t)); } } List<Integer> list = map(Arrays.asList("hello","world","Jesmin"),(String s) -> s.length());
接下来我们来一起总结一些常用的Lambda的例子以及可以使用的函数式接口。
使用案例 | Lambda示例 | 对应的函数式接口 |
布尔表达式 | (List<String> list) -> list.isEmpty() | Predicate<List<String>> |
创建对象 | ( ) -> new String() | Supplier<String> |
消费一个对象 | ( String s ) -> { System.out.println(s);} | Consumer<String> |
从某个对象中抽取属性 | ( Student s ) -> s.getHeight() | Function<Student,Integer>或ToIntFunction<Student> |
组合两个值 | ( int a, int b ) -> a*b | IntBinaryOperator |
比较两个对象 | ( Student s1, Student s2 ) -> s1.getHeight().compareTo(s2.getHeight()) | Comparator<Student> |
List<Student> result = filter(students, (Student s) -> s.getHeight()>=180));
但实际上Lambda表达式也允许我们使用自由变量(不允许当作参数,可以在主体中使用外层作用域中定义的变量),如:
int num = 5; Runnable r = () -> System.out.println(num);
Lambda表达式同样能够在主体中使用实例变量和静态变量。但是局部变量必须显式声明为final或事实上为final,换句话说,Lambda表达式主体中使用过的局部变量,不能被再次赋值。
错误示范:
int num = 5; Runnable r = () -> System.out.println(num);
//此处编译会报错,因为被Lambda表达式主体引用的局部变量num被再次赋值了
num = 3;
相关文章推荐
- Java8 实战系列-03-lambda 表达式实战
- Java8 实战系列-02-lambda 表达式简介
- 「Java 8 函数式编程」读书笔记——lambda表达式
- java8实战二:Lambda 表达式
- java8实战:Lambda 表达式
- 读书笔记——《Java 8实战》系列之Lambda表达式(一)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(20)--嵌套类(Lambda 表达式--VS--方法引用)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(19)--嵌套类(Lambda 表达式)
- java8实战之Lambda表达式笔记
- Java8 实战系列-05-lambda 类型推断
- javaSE_8系列博客——Java语言的特性(三)--类和对象(21)--何时使用Lambda 表达式?
- Java8实战 — Lambda表达式详解
- Java 8系列之Lambda表达式
- 读书笔记——《Java 8实战》系列之行为参数化
- JavaSE_8系列博客——Java8的新特性(一)--Lambda表达式(1)--宏观把控
- 读书笔记——《Java 8实战》系列之方法引用
- Java若不为空则取其值的lambda表达式
- java lambda表达式学习笔记
- java8新特性--lambda表达式
- 北风课堂分享java项目实战系列视频教程