最近看尚硅谷java8新特性视屏,总结一下学习知识。
Lambda表达式:是一个匿名函数,我们可以把Lambda理解为一段可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码。作为一种更紧凑的风格,使java的表达能力得到了提升。
作为我这样的小白,看名词介绍是真的看不懂,下面贴上代码强化一下理解
package com.buerc.java8;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import org.junit.Test;
public class TestLambda1 {
//使用原来的匿名对象方式
@Test
public void test1() {
Comparator<String> com=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
};
TreeSet<String> t=new TreeSet<>(com);
t.add("hello");
t.add("world");
t.add("china");
t.add("Chinese");
System.out.println(t);
System.out.println("------------------");
TreeSet<String> t1=new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
});
t1.add("china");
t1.add("hello");
t1.add("world");
t1.add("Chinese");
System.out.println(t1);
}
//现在使用lambda表达式
@Test
public void test2() {
Comparator<String> com=(x,y)->Integer.compare(x.length(), y.length());
TreeSet<String> t=new TreeSet<>(com);
t.add("hello");
t.add("world");
t.add("china");
t.add("Chinese");
System.out.println(t);
System.out.println("------------------");
TreeSet<String> t1=new TreeSet<>((x,y)->Integer.compare(x.length(), y.length()));
t1.add("china");
t1.add("hello");
t1.add("world");
t1.add("Chinese");
System.out.println(t1);
}
//test1()和test2()对比很明显,lambda表达式一行就搞定,
//用之前的匿名内部类需要多行代码但真正有用的核心代码就一行
//Integer.compare(o1.length(), o2.length())
//一组员工信息
List<Employee> list=Arrays.asList(
new Employee(101, "张三", 18, 9999.99),
new Employee(102, "李四", 20, 6666.66),
new Employee(103, "王五", 25, 11111.11),
new Employee(104, "赵六", 40, 55555.55),
new Employee(105, "田七", 50, 99999.99)
);
//查询员工年龄小于40岁的
public List<Employee> filterEmployee(List<Employee> list){
List<Employee> temp=new ArrayList<>();
for(Employee emp:list) {
if(emp.getAge()<40) {
temp.add(emp);
}
}
return temp;
}
@Test
public void test3() {
List<Employee> temp=filterEmployee(list);
for(Employee emp:temp) {
System.out.println(emp);
}
}
//查询工资大于10000的员工
public List<Employee> filterEmployee1(List<Employee> list){
List<Employee> temp=new ArrayList<>();
for(Employee emp:list) {
if(emp.getSalary()>10000) {
temp.add(emp);
}
}
return temp;
}
@Test
public void test4() {
List<Employee> temp=filterEmployee1(list);
for(Employee emp:temp) {
System.out.println(emp);
}
}
//如果后期有新的需求例如查询id范围内的员工,此时需要再次新增方法
//但是代码存在冗余,真正变化的就只有一行代码emp.getXXX这个条件的变化
//而且我们在扩展功能的时候,最好在不修改目标对象的功能前提下,对目标功能扩展.
//针对新需求,新增方法显然对原代码进行了改动,这是需要尽量避免的
//所以我们有如下的优化方法
//优化方式一:策略设计模式
public List<Employee> filterEmployee( List<Employee> list,MyFilter<Employee> mf){
List<Employee> temp = new ArrayList<>();
for(Employee emp:list) {
if(mf.test(emp)) {//这里针对具体的需求来重写MyFilter接口的test方法即可
temp.add(emp);
}
}
return temp;
}
@Test
public void test5() {
List<Employee> temp1=filterEmployee(list,new EmployeeFilterByeAge());
for(Employee emp:temp1) {
System.out.println(emp);
}
System.out.println("---------------------------");
List<Employee> temp2=filterEmployee(list,new EmployeeFilterByeSalary());
for(Employee emp:temp2) {
System.out.println(emp);
}
//此种方法filterEmployee这个方法已经固定,
//后期新需求也只需实现MyFilter重写test即可
//但是这种模式每次新增一个需求就得新建一个实现了MyFilter的类
}
//优化方式二:匿名内部类
@Test
public void test6() {
List<Employee> temp1=filterEmployee(list,new MyFilter<Employee>() {
@Override
public boolean test(Employee t) {
return t.getId()>103;
}
});
for(Employee emp:temp1) {
System.out.println(emp);
}//这种方法虽然filterEmployee方法已经固定,有新需求后不用新增方法,
//也能进行功能扩充,也不会对原代码进行入侵,但是不够优雅
}
//优化方式三Lambda 表达式
@Test
public void test7() {
List<Employee> temp1=filterEmployee(list,(e)->e.getAge()<40);
temp1.forEach(System.out::println);
System.out.println("-------------------");
List<Employee> temp2=filterEmployee(list,(e)->e.getSalary()>10000);
temp2.forEach(System.out::println);
}
//优化方式四Stream API
@Test
public void test8() {
list.stream()
.filter((e)->e.getId()>103)
.forEach(System.out::println);
System.out.println("----------------------");
list.stream()
.map(Employee::getName)
.limit(3)
.sorted()
.forEach(System.out::println);
}
}
package com.buerc.java8;
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
public Employee(int id, String name, int age, double salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
super();
}
}
package com.buerc.java8;
//策略模式接口
public interface MyFilter<T> {
boolean test(T t);
}
package com.buerc.java8;
public class EmployeeFilterByeAge implements MyFilter<Employee>{
@Override
public boolean test(Employee t) {
return t.getAge()<40;
}
}
package com.buerc.java8;
public class EmployeeFilterByeSalary implements MyFilter<Employee>{
@Override
public boolean test(Employee t) {
return t.getSalary()>10000;
}
}
现在回过头来再来理解Lambda表达式
以前为了造个匿名内部类需要很多行代码,而真正我们有用的核心代码就一行,下图同样
使用Lambda表达式可以实现同样的效果,而且代码看起来更加优雅。因此Lambda表达式是一段可以传递的代码。
Lambda表达式语法:Lambda表达式在java语言中引入了一个新的语法元素和操作符“->”。称为Lambda操作符或箭头操作符,他将Lambda表达式分为了2部分
- 左侧:指定Lambda表达式需要的所有参数
- 右侧:指定Lambda体,即Lambda表达式要执行的功能
Lambda表达式语法:
* 左侧:Lambda 表达式的参数列表
* 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体 *
* 语法格式一:无参数,无返回值
* () -> System.out.println("Hello Lambda!"); *
* 语法格式二:有一个参数,并且无返回值
* (x) -> System.out.println(x) *
* 语法格式三:若只有一个参数,小括号可以省略不写
* x -> System.out.println(x) *
* 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
* Comparator<Integer> com = (x, y) -> {
* System.out.println("函数式接口");
* return Integer.compare(x, y);
* }; *
* 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
* Comparator<Integer> com = (x, y) -> Integer.compare(x, y); *
* 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
* (Integer x, Integer y) -> Integer.compare(x, y);
*
* 上联:左右遇一括号省
* 下联:左侧推断类型省
* 横批:能省则省
Lambda 表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
可以检查是否是函数式接口
* Java8 内置的四大核心函数式接口 *
* Consumer<T> : 消费型接口
* void accept(T t); *
* Supplier<T> : 供给型接口
* T get(); *
* Function<T, R> : 函数型接口
* R apply(T t); *
* Predicate<T> : 断言型接口
* boolean test(T t);
package com.buerc.java8;
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;
import org.junit.Test;
public class TestLambda2 {
//Consumer<T> 消费型接口 :
@Test
public void test1() {
play("购物",(str)->System.out.println(str));
//(str)->System.out.println(str)相当于重写了Consumer<T>的accept方法
}
public void play(String entertainment,Consumer<String> c) {
c.accept(entertainment);
}
//Supplier<T> 供给型接口 :
@Test
public void test2() {
List<Integer> list=getNum(10,()->(int)(Math.random()*100));
list.forEach(System.out::println);
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNum(int count,Supplier<Integer> sup){
List<Integer> list=new ArrayList<Integer>();
for (int i = 0; i < count; i++) {
Integer n=sup.get();
list.add(n);
}
return list;
}
//Function<T, R> 函数型接口:
@Test
public void test3() {
System.out.println(strHandler("hello world",(str)->str.toUpperCase()));//具体处理操作是进行大写转换
}
public String strHandler(String str,Function<String, String> fun) {
return fun.apply(str);//将str字符串处理后返回
}
//Predicate<T> 断言型接口:
@Test
public void test4() {
List<String> list=Arrays.asList("hello","www","main","ok");
for (String string : list) {
if(filterStr(string,(str)->str.length()>2)) {//具体判断操作是字符长度是否大于2
System.out.println(string);
}
}
}
public boolean filterStr(String str,Predicate<String> p) {
return p.test(str);//进行字符串的判断操作
}
}
今天的学习总结就到这,接着继续看视频学习。