Java8 Lambda表达式

资料 :
  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);	
	}
}

  

原文地址:https://www.cnblogs.com/jiuya/p/11810750.html