java8新特性总结——lambda表达式

时间:2022-07-11 19:13:27

最近看尚硅谷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表达式

java8新特性总结——lambda表达式java8新特性总结——lambda表达式

以前为了造个匿名内部类需要很多行代码,而真正我们有用的核心代码就一行,下图同样java8新特性总结——lambda表达式java8新特性总结——lambda表达式

使用Lambda表达式可以实现同样的效果,而且代码看起来更加优雅。因此Lambda表达式是一段可以传递的代码。

Lambda表达式语法:Lambda表达式在java语言中引入了一个新的语法元素和操作符“->”。称为Lambda操作符或箭头操作符,他将Lambda表达式分为了2部分

  1. 左侧:指定Lambda表达式需要的所有参数
  2. 右侧:指定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);//进行字符串的判断操作
	}
}
今天的学习总结就到这,接着继续看视频学习。