资料 :
1.java8新特性(拉姆达表达式lambda) *****
https://blog.csdn.net/qq_35805528/article/details/53264301
1.Java8 Lambda表达式教程 ***
https://blog.csdn.net/ioriogami/article/details/12782141
2.【java8新特性】兰姆达表达式 ***
https://blog.csdn.net/DJuan15732626157/article/details/80251401
我们要注意的是:lambda表达式需要“函数式接口”的支持,那么什么是函数式接口呢?函数式接口:接口只有一个抽象方法的接口,
java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断,
但最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。
这是Java8新引入的概念。它的定义是:一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数接口。一般用@FunctionalInterface标注出来(也可以不标)。
举例如下:
@FunctionalInterface
public interface Runnable { void run(); }
public interface Callable<V> { V call() throws Exception; }
public interface ActionListener { void actionPerformed(ActionEvent e); }
public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
注意最后这个Comparator接口。它里面声明了两个方法,貌似不符合函数接口的定义,但它的确是函数接口。这是因为equals方法是Object的,
所有的接口都会声明Object的public方法——虽然大多是隐式的。所以,Comparator显式的声明了equals不影响它依然是个函数接口。
你可以用一个lambda表达式为一个函数接口赋值:
Runnable r1 = () -> {System.out.println("Hello Lambda!");};
然后再赋值给一个Object:
Object obj = r1;
但却不能这样干:
Object obj = () -> {System.out.println("Hello Lambda!");}; // ERROR! Object is not a functional interface!
必须显式的转型成一个函数接口才可以:
Object o = (Runnable) () -> { System.out.println("hi"); }; // correct
一个lambda表达式只有在转型成一个函数接口后才能被当做Object使用。所以下面这句也不能编译:
System.out.println( () -> {} ); //错误! 目标类型不明
必须先转型:
System.out.println( (Runnable)() -> {} ); // 正确
假设你自己写了一个函数接口,长的跟Runnable一模一样:
@FunctionalInterface
public interface MyRunnable {
public void run();
}
那么
Runnable r1 = () -> {System.out.println("Hello Lambda!");};
MyRunnable2 r2 = () -> {System.out.println("Hello Lambda!");};
都是正确的写法。这说明一个lambda表达式可以有多个目标类型(函数接口),只要函数匹配成功即可。
但需注意一个lambda表达式必须至少有一个目标类型。
lambda语法
包含三部分:
1、一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数
2、一个箭头符号:->
3、方法体,可以是表达式和代码块。
public class Demo1 {
public static void main(String[] args) {
runThreadByLambda();
runThreadByInnerClass();
}
public static void runThreadByLambda() {
/*
Runnable就是一个函数式接口:他只有一个方法run()方法。
1、因为run()方法没有参数,所以 ->前面的()中不需要声明形参
2、run返回的是void,所以不需要return。
3、->后面写的代码其实就是定义在run方法内的代码。因为此处代码只有一行,所以{}也可以省略。如果此处多与一行,则无法省略。
*/
Runnable runnable = () -> System.out.println("这个是用拉姆达实现的线程");
new Thread(runnable).start();
}
public static void runThreadByInnerClass() {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("这个是用内部类实现的线程");
}
};
new Thread(runnable).start();
}
}
lambda方法引用
其实是lambda表达式的一种简化写法。所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名。
一般方法的引用格式:
如果是静态方法,则是ClassName::methodName。如 Object ::equals
如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
构造函数.则是ClassName::new
public class Demo2 {
public static void main(String[] args) {
/*
* 方法引用
*/
Runnable runnable = Demo2::run;
new Thread(runnable).start();
}
public static void run(){
System.out.println("方法引用的代码...");
}
}
使用lambda改进的集合框架
import java.util.ArrayList;
import java.util.List;
public class Demo3 {
public static void main(String[] args) {
List<User> users = new ArrayList<User>();
users.add(new User(20, "张三"));
users.add(new User(22, "李四"));
users.add(new User(10, "王五"));
users.forEach((User user) -> System.out.println(user.getAge()));
}
}
Stream API
流(Stream)仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历(这点在编程时候需要注意,不像Collection,遍历多少次里面都还有数据),它的来源可以是Collection、array、io等等。
流作用是提供了一种操作大数据接口,让数据操作更容易和更快。它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法和终端方法,“流”抽象天生就该是持续的,中间方法永远返回的是Stream,
因此如果我们要获取最终结果的话,必须使用终点操作才能收集流产生的最终结果。区分这两个方法是看他的返回值,如果是Stream则是中间方法,否则是终点方法。
filter
在数据流中实现过滤功能是首先我们可以想到的最自然的操作了。Stream接口暴露了一个filter方法,它可以接受表示操作的Predicate实现来使用定义了过滤条件的lambda表达式。
import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "张三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); stream.filter(p -> p.getAge() > 20); //过滤年龄大于20的 } }
map
假使我们现在过滤了一些数据,比如转换对象的时候。Map操作允许我们执行一个Function的实现(Function<T,R>的泛型T,R分别表示执行输入和执行结果),它接受入参并返回。
import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "张三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); //所有的年龄大于20岁的User对象,转换为字符串50对象。现在流中只有字符串对象了。 stream.filter((User user) -> user.getAge() > 20).map((User user) -> {return "50";}); } }
count
count方法是一个流的终点方法,可使流的结果最终统计,返回long
import java.util.ArrayList; import java.util.List; import java.util.stream.Collector; import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "张三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); long count = stream.filter((User user) -> user.getAge() >= 20).map((User user) -> {return "50";}) .count(); //返回流中元素的个数。 System.out.println(count); } }