Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
//原来的匿名内部类
@Test
public void test1(){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(comparator);
}
//Lambda表达式
@Test
public void test2(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> ts = new TreeSet<>(comparator);
}
员工实体类
package com.xxxx.lln;
/**
* 员工实体
*/
public class Employee {
private String name;
private int age;
private double salary;
public Employee() {
}
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
定义员工集合
//员工集合
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,6666.66),
new Employee("王五",35,5555.55),
new Employee("赵六",13,3333.33),
new Employee("田七",26,8888.88)
);
需求1:获取年龄大于35的员工信息
//过滤
public List<Employee> filterEmployees(List<Employee> list){
List<Employee> emps =new ArrayList<>();
for (Employee emp : list) {
if (emp.getAge()>=35){
emps.add(emp);
}
}
return emps;
}
//调用
@Test
public void test3(){
List<Employee> list = filterEmployees(employees);
for(Employee emp : list){
System.out.println(emp.toString());
}
}

需求2:获取工资大于5000的员工信息
//过滤
public List<Employee> filterEmployees2(List<Employee> list){
List<Employee> emps =new ArrayList<>();
for (Employee emp : list) {
if (emp.getSalary()>=5000){//只改变了方法名和这一句
emps.add(emp);
}
}
return emps;
}
//调用
......
每次都要写过滤函数,太麻烦了
定义一个接口类
package com.xxxx.lln;
/**
* 接口类
* @param
*/
public interface MyPredicate<T>{
public boolean test(T t);
}
定义过滤的方法函数
//过滤员工,需要传入员工集合和过滤条件的接口类
public List<Employee> filterEmployee(List<Employee> list , MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<>();
for (Employee employee:list) {
if (mp.test(employee)){
emps.add(employee);
}
}
return emps;
}
需要的时候去实现接口类
package com.xxxx.lln;
/**
* 过滤年龄大于35
*/
public class FilterEmployeeByAge implements MyPredicate<Employee>{
@Override
public boolean test(Employee employee) {
return employee.getAge()>=35;
}
}
/**
* 过滤工资大于5000
*/
public class FilterEmployeeBySalary implements MyPredicate<Employee>{
@Override
public boolean test(Employee employee) {
return employee.getSalary()>=5000;
}
}
调用:
@Test
public void test4(){
List<Employee> list = filterEmployee(employees,new FilterEmployeeByAge());
for (Employee employee : list) {
System.out.println(employee);
}
System.out.println("------------------------------------");
List<Employee> list2 = filterEmployee(employees,new FilterEmployeeBySalary());
for (Employee employee : list2) {
System.out.println(employee);
}
}

@Test
public void test5(){
List<Employee> list = filterEmployee(employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>=5000;
}
});
for (Employee employee : list){
System.out.println(employee);
}
}

//语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)
@Test
public void test6(){
//仍需要调用过滤的那个接口
List<Employee> list = filterEmployee(employees,(e) -> e.getSalary() >= 5000);
list.forEach(System.out::println);
}

@Test
public void test7(){
//不需要用上面的接口
employees.stream()
.filter((e) -> e.getSalary() >= 5000)
.limit(2)//取前两个
.forEach(System.out::println);
System.out.println("---------------------------");
//把所有名字拿出来
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}

Lambda 表达式在Java 语言中引入了一个新的语法元 素和操作符。这个操作符为 -> , 该操作符被称 为 Lambda 操作符或剪头操作符。
它将 Lambda 分为 两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。


这里给出六个接口,后文的全部操作都利用这六个接口来进行阐述。
/**多参数无返回*/
@FunctionalInterface
public interface NoReturnMultiParam {
void method(int a, int b);
}
/**无参无返回值*/
@FunctionalInterface
public interface NoReturnNoParam {
void method();
}
/**一个参数无返回*/
@FunctionalInterface
public interface NoReturnOneParam {
void method(int a);
}
/**多个参数有返回值*/
@FunctionalInterface
public interface ReturnMultiParam {
int method(int a, int b);
}
/*** 无参有返回*/
@FunctionalInterface
public interface ReturnNoParam {
int method();
}
/**一个参数有返回值*/
@FunctionalInterface
public interface ReturnOneParam {
int method(int a);
}
语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)。
import lambda.interfaces.*;
public class Test1 {
public static void main(String[] args) {
//无参无返回
NoReturnNoParam noReturnNoParam = () -> {
System.out.println("NoReturnNoParam");
};
noReturnNoParam.method();
//一个参数无返回
NoReturnOneParam noReturnOneParam = (int a) -> {
System.out.println("NoReturnOneParam param:" + a);
};
noReturnOneParam.method(6);
//多个参数无返回
NoReturnMultiParam noReturnMultiParam = (int a, int b) -> {
System.out.println("NoReturnMultiParam param:" + "{" + a +"," + + b +"}");
};
noReturnMultiParam.method(6, 8);
//无参有返回值
ReturnNoParam returnNoParam = () -> {
System.out.print("ReturnNoParam");
return 1;
};
int res = returnNoParam.method();
System.out.println("return:" + res);
//一个参数有返回值
ReturnOneParam returnOneParam = (int a) -> {
System.out.println("ReturnOneParam param:" + a);
return 1;
};
int res2 = returnOneParam.method(6);
System.out.println("return:" + res2);
//多个参数有返回值
ReturnMultiParam returnMultiParam = (int a, int b) -> {
System.out.println("ReturnMultiParam param:" + "{" + a + "," + b +"}");
return 1;
};
int res3 = returnMultiParam.method(6, 8);
System.out.println("return:" + res3);
}
}
Lambda 语法简化
我们可以通过观察以下代码来完成代码的进一步简化,写出更加优雅的代码。
import lambda.interfaces.*;
public class Test2 {
public static void main(String[] args) {
//1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
NoReturnMultiParam lamdba1 = (a, b) -> {
System.out.println("简化参数类型");
};
lamdba1.method(1, 2);
//2.简化参数小括号,如果只有一个参数则可以省略参数小括号
NoReturnOneParam lambda2 = a -> {
System.out.println("简化参数小括号");
};
lambda2.method(1);
//3.简化方法体大括号,如果方法条只有一条语句,则可以省略方法体大括号
NoReturnNoParam lambda3 = () -> System.out.println("简化方法体大括号");
lambda3.method();
//4.如果方法体只有一条语句,并且是 return 语句,则可以省略方法体大括号
ReturnOneParam lambda4 = a -> a+3;
System.out.println(lambda4.method(5));
ReturnMultiParam lambda5 = (a, b) -> a+b;
System.out.println(lambda5.method(1, 1));
}
}
上述 Lambda 表达式中的参数类型都是由编译器推断 得出的。Lambda 表达式中无需指定类型,程序依然可 以编译,这是因为 javac 根据程序的上下文,在后台 推断出了参数的类型。Lambda 表达式的类型依赖于上 下文环境,是由编译器推断出来的。这就是所谓的 “ 类型推断”。
什么是函数式接口
@FunctionalInterface
public interface MyNumber{
public double getValue();
}
函数式接口中使用泛型:
@FunctionalInterface
public interface MyFunction<T>{
public T getValue();
}
public String toUpperString(MyFunction<String> m,String s){
return m.getValue(s);
}
//作为参数传递
String newStr = toUpperString((str)->str.toUpperCase(),"abcdef");
System.out.println(newStr);
需求:对一个数进行运算
@FunctionalInterface
public interface MyFunction {
public Integer getValue(Integer num);
}
public Integer operation(Integer num , MyFunction m){
return m.getValue(num);
}
@Test
public void test(){
Integer num = operation(100,x -> x * x);
System.out.println(num);
System.out.println(operation(200,x -> x+300));
}


当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:


注意:当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时:ClassName::methodName
//对象::实例方法名
//Consumer con = x -> System.out.println(x);
Consumer<String> con = System.out::println;
con.accept("asdfghjkl");
System.out.println("------------------------------------");
Employee emp = new Employee("lln",18,999);
//Supplier supplier = () -> emp.getName();
Supplier<String> supplier = emp::getName;
System.out.println(supplier.get());
System.out.println("------------------------------------");
//类::静态方法名
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
//Comparator com = Integer::compare;
System.out.println(com.compare(1,2));
System.out.println("------------------------------------");
//类::实例方法名
//BiPredicate bp = (x,y)->x.equals(y);
//规则:第一个参数是方法的调用者,第二个参数是要调用方法的参数时,可以使用类::实例方法名
BiPredicate<String,String> bp = String::equals;
构造器引用
与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,构造器参数列表要与接口中抽象方法的参数列表一致!
ClassName::new

interface ItemCreatorBlankConstruct {
Item getItem();
}
interface ItemCreatorParamContruct {
Item getItem(int id, String name, double price);
}
public class Exe2 {
public static void main(String[] args) {
ItemCreatorBlankConstruct creator = () -> new Item();
Item item = creator.getItem();
ItemCreatorBlankConstruct creator2 = Item::new;
Item item2 = creator2.getItem();
ItemCreatorParamContruct creator3 = Item::new;
Item item3 = creator3.getItem(112, "鼠标", 135.99);
}
}
数组引用

//数组引用
//Function fun = (x) -> new String[x];
Function<Integer,String[]> fun = String[]::new;
String[] strs = fun.apply(10);
System.out.println(strs.length);
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一 个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对 集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。
也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

1.可以通过Collection系列集合提供的stream()或parallelStream()
Java8 中的 Collection 接口被扩展,提供了 两个获取流的方法:
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
2.由数组创建
Java8 中的 Arrays 的静态方法 stream() 可 以获取数组流:
static Stream stream(T[] array): 返回一个流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
3.由值创建流
通过Stream类中的静态方法of()
可以使用静态方法 Stream.of(), 通过显示值 创建一个流。它可以接收任意数量的参数。
Stream<String> stream3 = Stream.of("aa","bb","cc");
4.由函数创建流:创建无限流
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
迭代 public static Stream iterate(final T seed, final UnaryOperator f)
生成 public static Stream generate(Supplier s) :
//迭代
Stream<Integer> stream4 = Stream.iterate(0,(x) -> x + 2);
stream4.limit(10)
.forEach(System.out::println);
//生成
Stream.generate(()->Math.random())
.limit(5)
.forEach(System.out::println);
多个中间操作可以连接起来形成一个流水线,除非流水 线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理,称为“惰性求值”。
//员工集合
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,6666.66),
new Employee("王五",35,5555.55),
new Employee("赵六",13,3333.33),
new Employee("田七",26,8888.88)
);
//内部迭代:迭代操作由Stream API完成
@Test
public void test1(){
//中间操作:不会执行任何操作
Stream<Employee> stream = employees.stream()
.filter((e)->e.getAge()>35);
//终止操作:一次性执行全部内容,即“惰性求值”
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test2(){
Iterator<Employee> it = employees.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
筛选与切片

@Test
public void test3(){
employees.stream()
.filter((e)->e.getSalary()>5000)
.limit(2)
.forEach(System.out::println);
}
//只要迭代到满足条件的两个数据后,后续操作就不进行了
@Test
public void test4(){
employees.stream()
.filter((e)->e.getSalary()>5000)
//跳过前两个满足条件的数据
.skip(2)
.forEach(System.out::println);
}
去重
@Test
public void test5(){
employees.stream()
.filter((e)->e.getSalary()>5000)
.distinct()
.forEach(System.out::println);
}
映射

@Test
public void test6(){
List<String> list = Arrays.asList("aaa","bbb","ccc");
list.stream()
.map((str)->str.toUpperCase())
.forEach(System.out::println);
System.out.println("--------------------");
//提取名字
employees.stream()
.map(Employee::getName)
.distinct()
.forEach(System.out::println);
}
flatMap
@Test
public void test7(){
List<String> list = Arrays.asList("aaa","bbb","ccc");
// {{a,a,a},{b,b,b},{c,c,c}}
// Stream> stream = list.stream()
// .map(TestStreamAPI2::filterCharacter);
//
// stream.forEach((sm)->{
// sm.forEach(System.out::println);
// });
System.out.println("-----------------------");
//{a,a,a,b,b,b,c,c,c}
Stream<Character> sm = list.stream()
.flatMap(TestStreamAPI2::filterCharacter);
sm.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()){
list.add(ch);
}
return list.stream();
}
排序

终端操作会从流的流水线生成结果。其结果可以是任何不是流的 值,例如:List、Integer,甚至是 void 。
查找和匹配
allMatch——检查是否匹配所有元素 传入断定型接口
anyMatch——检查是否至少匹配一个元素 传入断定型接口
noneMatch——检查是否没有匹配的元素 传入断定型接口
findFirst——返回第一个元素
findAny——返回当前流中的任意一个元素
count——返回流中元素的总个数
max——返回流中最大值 传入Comparator接口
min——返回流中最小值 传入Comparator接口