一、案例分析
1、创建实体类 Employee
package com.lambda1;
public class Employe {
private String name;
private int age;
private double salary;
public Employe() {
}
public Employe(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 "Employe{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
2、创建测试类 TestLambda2.java
package com.lambda1;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestLambda2 {
List<Employe> employes = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77)
);
@Test
public void test1(){
//按年龄过滤
List<Employe> list = filterEmployee(employes);
list.forEach(System.out::println);
System.out.println("--------------------------------------------------");
//按工资过滤
List<Employe> list2 = filterEmployee2(employes);
list2.forEach(System.out::println);
}
//需求1:获取当前公司中员工年龄大于35的员工信息
public List<Employe> filterEmployee(List<Employe> list){
List<Employe> emps = new ArrayList<>();
for (Employe emp: list){
if (emp.getAge() >= 35){
emps.add(emp);
}
}
return emps;
}
//需求2:获取当前公司中员工工资大于5000的员工信息
public List<Employe> filterEmployee2(List<Employe> list){
List<Employe> emps = new ArrayList<>();
for (Employe emp: list){
if (emp.getSalary() >= 5000){
emps.add(emp);
}
}
return emps;
}
}
分析:上述需求中每增加一个类似的需求就要创建一个新的对应的处理方法,方法中真正有作用的地方在 if(...) 的判断中,这样造成代码冗余。
3、对 TestLambda2.java中代码优化方式《一》
优化方案一: 采用设计者模式优化
3.1创建公共接口 MyPredicate.java 接口
package com.lambda1;
public interface MyPredicate<T> {
public boolean test(T t);
}
3.2 创建FilterEmployeeByAge.java 过滤年龄的方法,实现接口 MyPredicate.java
package com.lambda1;
public class FilterEmployeeByAge implements MyPredicate<Employe>{
@Override
public boolean test(Employe t) {
return t.getAge() >= 35;
}
}
3.3 创建FilterEmployeeBySalary.java 过滤薪水的方法,实现接口 MyPredicate.java
package com.lambda1;
public class FilterEmployeeBySalary implements MyPredicate<Employe>{
@Override
public boolean test(Employe t) {
return t.getSalary()>=5000;
}
}
3.4 优化后的 TestLambda2.java 类
package com.lambda1;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestLambda2 {
List<Employe> employes = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77)
);
//优化方式一:策略设计者模式
@Test
public void test2(){
//按年龄过滤
List<Employe> list = filterEmployee(this.employes, new FilterEmployeeByAge());
list.forEach(System.out::println);
System.out.println("--------------------------------------------------");
//按工资过滤
List<Employe> list2 = filterEmployee(this.employes, new FilterEmployeeBySalary());
list2.forEach(System.out::println);
}
public List<Employe> filterEmployee(List<Employe> list, MyPredicate<Employe> mp){
List<Employe> emps = new ArrayList<>();
for (Employe employe : list){
if (mp.test(employe)){
emps.add(employe);
}
}
return emps;
}
}
优化方式一存在的问题:每次添加一个需求方法,都要添加一个对应实现接口 MyPredicate.java 的 FilterEmployeeByXxx.java类;
4、对 TestLambda2.java中代码优化方式《二》
优化方案二:采用匿名内部类方式
//优化方式二:匿名内部类
@Test
public void test3(){
List<Employe> list = filterEmployee(this.employes, new MyPredicate<Employe>() {
@Override
public boolean test(Employe t) {
return t.getAge() >= 30;
}
});
list.forEach(System.out::println);
System.out.println("---------------------------------------");
List<Employe> list2 = filterEmployee(this.employes, new MyPredicate<Employe>() {
@Override
public boolean test(Employe t) {
return t.getSalary() >= 5000;
}
});
list2.forEach(System.out::println);
}
public List<Employe> filterEmployee(List<Employe> list, MyPredicate<Employe> mp){
List<Employe> emps = new ArrayList<>();
for (Employe employe : list){
if (mp.test(employe)){
emps.add(employe);
}
}
return emps;
}
优化方式二中存在的问题:代码中关键部位只有 t.getAge() >= 30 和 t.getSalary() >= 5000,其余部分都是多余的;
4、对 TestLambda2.java中代码优化方式《三》
//优化方式三:采用Lambda表达式
@Test
public void test4(){
List<Employe> list = filterEmployee(this.employes, t -> t.getAge() >= 30);
list.forEach(System.out::println);
System.out.println("---------------------------------------");
List<Employe> list2 = filterEmployee(this.employes, t -> t.getSalary() >= 5000);
list2.forEach(System.out::println);
}
public List<Employe> filterEmployee(List<Employe> list, MyPredicate<Employe> mp){
List<Employe> emps = new ArrayList<>();
for (Employe employe : list){
if (mp.test(employe)){
emps.add(employe);
}
}
return emps;
}
优化方式三中存在的问题:在过滤的过程中需要创建接口 MyPredicate.java 并且需要方法 filterEmployee()。
4、对 TestLambda2.java中代码优化方式《五》
优化方式五:采用 Stream API
//优化方式四
@Test
public void test5(){
this.employes.stream()
.filter(x->x.getAge()>=30)
.forEach(System.out::println);
System.out.println("--------------------------------------");
this.employes.stream()
.filter(x->x.getSalary()>=5000)
.forEach(System.out::println);
}
二、Lambda 表达式语法
Lambda 是一个匿名函数,可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。
Java8引入了一个新的操作符 “->” 该操作符称为箭头符或lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:
左侧:Lambda 表达式的参数列表;
右侧:Lambda 表达式中所需要执行的功能,即 Lambda 体;
例子1:
package com.lambda1;
import org.junit.Test;
import java.util.Comparator;
import java.util.TreeSet;
public class TestLambda {
//原来匿名内部类
@Test
public void test1(){
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
//Lambda表达式
@Test
public void test2(){
Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
TreeSet<Integer> ts = new TreeSet<>(com);
}
}
三、Lambda 表达式练习
package com.lambda2;
import com.lambda1.Employe;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Lambda表达式练习
*/
public class TestLambda1 {
List<Employe> emps = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77),
new Employe("田八", 10,7777.77)
);
//需求:按员工年龄排序,年龄相同按姓名排序
@Test
public void test1(){
Collections.sort(emps, (x, y) -> {
if (x.getAge() == y.getAge()){
return x.getName().compareTo(y.getName());
}else{
return -Integer.compare(x.getAge(),y.getAge());
}
});
emps.forEach(System.out::println);
}
}
存在问题:使用 Lambda 表达式需要函数式接口的支持;
函数式接口:接口中只有一个抽象方法(Object类中的方法忽略)。或者使用了@FunctionInterface 注解的接口,为函数式接口。
四、Java8中内置的四大核心函数式接口
java8 内置的四大核心函数式接口
1.Consumer<T>:消费型接口
void accept(T t);2.Supplier<T>: 供给型接口
T get();3.Function<T, R>:函数型接口
R apply(T t);4.Predicate<T>:断言型接口
boolean test(T t);
package com.lambda2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* java8 内置的四大核心函数式接口
*
* 1.Consumer<T>:消费型接口
* void accept(T t);
*
* 2.Supplier<T>: 供给型接口
* T get();
*
* 3.Function<T, R>:函数型接口
* R apply(T t);
*
* 4.Predicate<T>:断言型接口
* boolean test(T t);
*
*/
public class TestLambda3 {
//Consumer<T>:消费型接口
@Test
public void test1(){
happy(1000, m-> System.out.println("吃饭消费:"+m));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//Supplier<T>: 供给型接口
@Test
public void test2(){
List<Integer> list = getNumList(10, () -> (int)(Math.random() * 100));
list.forEach(System.out::println);
}
//需求:产生一个集合里面都是整数
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i=0; i<num; i++){
list.add(sup.get());
}
return list;
}
//Function<T, R>:函数型接口
@Test
public void test3(){
String s1 = strHandle("\t\t\t 你好,中国! ", s -> s.trim());
System.out.println(s1);
String s2 = strHandle("abcdf", s -> s.toUpperCase());
System.out.println(s2);
}
//需求:用于处理字符串
public String strHandle(String str, Function<String, String> fun){
return fun.apply(str);
}
//Predicate<T>:断言型接口
@Test
public void test4(){
List<String> list = Arrays.asList("hello","www","lambda","ok");
List<String> resList = filterStr(list, s -> s.length() > 3);
resList.forEach(System.out::println);
}
//取出满足条件的字符串
public List<String> filterStr(List<String> list, Predicate<String> pred){
List<String> strList = new ArrayList<>();
for(String str : list){
if (pred.test(str)){
strList.add(str);
}
}
/* list.forEach(x-> {
if (pred.test(x)){
strList.add(x);
}
});
*/
return strList;
}
}
五、Java8 中方法引用
一、方法引用:若 Lambda 体内的内容有方法已经实现了, 我们可以使用“方法引用”
(可以理解为方法引用时 Lambda 表达式的另外一种表现形式)主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
注意:
(1)Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数式列表和返回值类型保持一致!
(2)Lambda 参数列表中第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName::method二、构造器引用
格式:ClassName::new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一致!三、数组引用
格式:Type::new
package com.TestMethodRef;
import com.lambda1.Employe;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 一、方法引用:若 lambda 体内的内容有方法已经实现了, 我们可以使用“方法引用”
* (可以理解为方法引用时 Lambda 表达式的另外一种表现形式)
*
* 主要有三种语法格式:
*
* 对象::实例方法名
*
* 类::静态方法名
*
* 类::实例方法名
*
* 注意:(1)Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数式列表和返回值类型保持一致!
* (2)Lambda 参数列表中第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName::method
*
* 二、构造器引用
* 格式:ClassName::new
* 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一致!
*
* 三、数组引用
* 格式:Type::new
*/
public class TestMethodRef {
//对象::实例方法名
@Test
public void test1(){
PrintStream ps = System.out;
//Lambda表达式
Consumer<String> con = x -> ps.println(x);
// Consumer<String> con = System.out::println;
PrintStream ps1 = System.out;
//方法引用
Consumer<String> con1 = ps1::println;
Consumer<String> con2 = System.out::println;
con2.accept("abcd");
}
@Test
public void test2(){
Employe emp = new Employe("赵云", 20,8888.88);
//Lambda表达式
Supplier<String> sup = ()-> emp.getName();
String s = sup.get();
System.out.println(s);
//方法引用
Supplier<Integer> sup2 = emp::getAge;
Integer s2 = sup2.get();
System.out.println(s2);
}
//类::静态方法名
@Test
public void test3(){
//Lambda表达式
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
int r = com.compare(10, 5);
System.out.println(r);
//方法引用
Comparator<Integer> com2 = Integer::compare;
int r2 = com2.compare(5, 10);
System.out.println(r2);
}
//类::实例方法名
@Test
public void test4(){
//Lambda表达式
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
//方法引用(规则:第一个参数是实例方法的调用者,第二个参数是实例方法的参数)
BiPredicate<String, String> bp2 = String::equals;
}
//构造器引用
@Test
public void test5(){
//Lambda 表达式
Supplier<Employe> sup = ()-> new Employe();
//构造器引用
Supplier<Employe> sup2 = Employe::new;
}
//数组引用
@Test
public void test6(){
//Lambda 表达式
Function<Integer, String[]> fun = (x)-> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
//数组引用
Function<Integer, String[]> fun2 = String[]::new;
String[] strs2 = fun.apply(8);
System.out.println(strs2.length);
}
}