012—JAVA8新特性(lambda表达式)
2021/11/7 1:10:06
本文主要是介绍012—JAVA8新特性(lambda表达式),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
函数式编程(lambda表达式 @FunctionalInterface)
思想:(函数式编程VS面向对象)
函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。编程中的函数,也有类似的概念,你调用我的时候,给我实参为形参赋值,然后通过运行方法体,给你返回一个结果。对于调用者来做,关注这个方法具备什么样的功能。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。
面向对象的思想:
做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情.
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程
优点:
目的是简化匿名内部类
Lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的匿名内部类。
冗余的匿名内部类
public class Demo01Runnable { public static void main(String[] args) { // 匿名内部类 Runnable task = new Runnable() { @Override public void run() { // 覆盖重写抽象方法 System.out.println("多线程任务执行!"); } }; new Thread(task).start(); // 启动线程 } }
分析弊端:
对于
Runnable
的匿名内部类用法,可以分析出几点内容:
Thread
类需要Runnable
接口作为参数,其中的抽象run
方法是用来指定线程任务内容的核心;为了指定
run
的方法体,不得不需要Runnable
接口的实现类;为了省去定义一个
RunnableImpl
实现类的麻烦,不得不使用匿名内部类;必须覆盖重写抽象
run
方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;而实际上,似乎只有方法体才是关键所在。
编程思想转换
做什么,而不是谁来做,怎么做 (关注点不同)
我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将
run
方法体内的代码传递给Thread
类知晓。传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。那,有没有更加简单的办法?如果我们将关注点从“怎么做”回归到“做什么”的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。
函数式编程面向的主要场景是,针对于函数式接口(@FunctionalInterface,即接口中只含有一个抽象方法,对于静态方法和default方法没有限制).
了解函数式接口:
写法:
针对于抽象方法,省略方法声明,只要参数,和方法体,如果方法体只有一个语句也可以省略{},否则可以省略。
()->{}
():形参
->: 语法标识
{}:方法体注意:
1.如果方法重写后 仅有一行代码 可以省略{}
2.()数据类型可以省略
3.如果带返回值的方法 只有一行返回语句
那么可以省略 return {};
(形参列表)它就是你要赋值的函数式接口的抽象方法的(形参列表),照抄
{Lambda体}就是实现这个抽象方法的方法体
->称为Lambda操作符(减号和大于号中间不能有空格,而且必须是英文状态下半角输入方式)
优化:Lambda表达式可以精简
当{Lambda体}中只有一句语句时,可以省略{}和{;}
当{Lambda体}中只有一句语句时,并且这个语句还是一个return语句,那么return也可以省略,但是如果{;}没有省略的话,return是不能省略的
(形参列表)的类型可以省略
当(形参列表)的形参个数只有一个,那么可以把数据类型和()一起省略,但是形参名不能省略
当(形参列表)是空参时,()不能省略
lambda表达式其实就是实现SAM接口的语法糖,所谓SAM接口就是Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法。为了简化匿名内部类的写的方式
其实只要满足“SAM”特征的接口都可以称为函数式接口,都可以使用Lambda表达式,但是如果要更明确一点,最好在声明接口时,加上@FunctionalInterface。一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。
之前学过的SAM接口中,标记了@FunctionalInterface的函数式接口的有:Runnable,Comparator 。
Java8在java.util.function新增了很多函数式接口:主要分为四大类,消费型、供给型、判断型、功能型。基本可以满足我们的开发需求。当然你也可以定义自己的函数式接口。
函数式编程只关注结果
函数式接口的分类:
(一)自定义函数式接口
系统类的函数式接口:
@FunctionalInterface
public interface Runnable {}
@FunctionalInterface
public interface Comparator<T> {}public interface Comparable<T> {}只有一个抽象方法
系统函数式接口的分类:
消费型 貔貅 只进不出 只接受数据 不返回数据
供给型接口 雷锋 只奉献不索取 只返回数据 不接受数据
判断/断言型接口 法官 判断对错 无论接受什么数据 都只返回 boolean功能型接口 普通人 有来有往 既接受数据 也返回数据
只要确保接口中有且仅有一个抽象方法即可。
public class AutoDefination { public static void main(String[] args) { A a = new A() { @Override public void add(int a, int b) { System.out.println(a + b); } }; a.add(100, 200); } @Test public void test02(){ //lambda表达式只对抽象接口起作用 testAdd(100, 200, (a,b) -> System.out.println(a + b)); } @Test public void test01(){ testAdd(100, 200, new A() { @Override public void add(int a, int b) { System.out.println(a + b); } }); } public static void testAdd(int a,int b,A c){ c.add(a, b); } } @FunctionalInterface interface A{ //创建抽象方法 void add(int a,int b); }
(二)消费型接口
消费型接口的抽象方法特点:有形参,但是返回值类型是void
举例(list遍历和map遍历lambda)
list遍历
public class ConsumerTest { ArrayList<String> list = new ArrayList<>(); @Before public void test00(){ Collections.addAll(list, "A","B","C","D","E"); } @Test public void test06(){ } @Test public void test05(){ list.forEach((s) -> System.out.println(s)); ; } @Test public void test03(){ //会从传入参数的前一个位置开始遍历 ListIterator<String> listIterator = list.listIterator(list.size()); while (listIterator.hasPrevious()){ String current = listIterator.previous(); System.out.println("current = " + current); } } @Test public void test02(){ Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String next = iterator.next(); System.out.println("next = " + next); } } @Test public void test01(){ for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } }
map遍历
public class TestMap { Map<Integer, String> map = new HashMap<>(); @Before public void test00(){ map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); map.put(5, "E"); } @Test public void test03(){ map.forEach(new BiConsumer<Integer, String>() { @Override public void accept(Integer integer, String s) { System.out.println(integer + "--->" + s); } }); } @Test public void test02(){ map.forEach((k , v) -> System.out.println(k + "---->" + v)); } @Test public void test01(){ Set<Integer> keys = map.keySet(); keys.forEach((key) -> System.out.println(key +"---->" + map.get(key))); } }
(三)供给型接口
这类接口的抽象方法特点:无参,但是有返回值
public class SupplierTest { @Test public void test03(){ // //生成数据 将数据进行展示 无限生成 /*Stream.generate(new Supplier<Object>() { @Override public Object get() { return new Date(); } }).forEach(new Consumer<Object>() { @Override public void accept(Object o) { System.out.println("o = " + o); } });*/ Stream.generate(() -> new Date()).forEach(System.out::println); } @Test public void test02(){ /*Supplier<Double> supplier = new Supplier<Double>() { @Override public Double get() { return Double.valueOf(Math.PI); } };*/ Supplier<Double> supplier = () -> Double.valueOf(Math.PI); Double aDouble = supplier.get(); System.out.println("aDouble = " + aDouble); } @Test public void test01(){ /*//返回一个对象 Supplier supplier = new Supplier() { @Override public Object get() { return new String("供给型接口作用是返回一个对象"); } };*/ Supplier supplier = () -> new String("供给型接口作用是返回一个对象"); Object o = supplier.get(); System.out.println("o = " + o); } }
(四)判断型 (用于过滤数据)
这里接口的抽象方法特点:有参,但是返回值类型是boolean结果。
public class PredicateTest { ArrayList<Integer> list = new ArrayList<Integer>(); @Before public void test00(){ Collections.addAll(list, 1,2,3,4,5,6,7,8,9,10); list.forEach((n)-> System.out.print(n + " ")); System.out.println(); System.out.println("-------------数据添加完毕-----------------"); } @Test public void test01(){ //删除 经过检验 返回值为true的值 /* //方式一 list.removeIf(new Predicate<Integer>() { @Override public boolean test(Integer integer) { //删除偶数 if (integer % 2 == 0){ return true; }else { return false; } } });*/ //方式二 // list.removeIf((integer) -> integer % 2 == 0? true:false); //方式三 list.removeIf((integer)->integer%2==0); } @After public void test000(){ System.out.println("------------数据处理完打印----------------"); list.forEach((n)-> System.out.print(n+ " ")); } }
(五)功能型
这类接口的抽象方法特点:既有参数又有返回值
public class FunctionTest { HashMap<Integer, String> map = new HashMap<>(); @Before public void test00() { map.put(1, "李白"); map.put(2, "安琪拉"); map.put(3, "白居易"); map.put(4, "李商隐"); map.put(5, "嬴政"); map.forEach((k, v) -> System.out.println(k + "--->" + v)); } @Test public void test04() { map.replaceAll((k,v)-> v.contains("李")?"妲己":v); } @Test public void test03() { map.replaceAll((k,v) -> { return v.contains("李")?"妲己":v; }); } @Test public void test02() { map.replaceAll((k, v) -> { if (v.contains("李")) { return "妲己"; } else { return v; } }); } @Test public void test01() { map.replaceAll(new BiFunction<Integer, String, String>() { @Override public String apply(Integer key, String value) { // System.out.println(key + "------>" + value); //只要value中有白 ,就要将此value替换成妲己 if (value.contains("白")) { return "妲己"; } //返回值会替换原有的value return value; } }); } @After public void test000() { System.out.println("-----------------"); map.forEach((k, v) -> System.out.println(k + "--->" + v)); } }
判断型接口 练习
public class Employee { private int id; private String name; private char gender; private int age; private double salary; public Employee(int id, String name, char gender, int age, double salary) { super(); this.id = id; this.name = name; this.gender = gender; this.age = age; this.salary = salary; } public Employee() { super(); } 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 char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } 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 + ", gender=" + gender + ", age=" + age + ", salary=" + salary + "]"; } }
public class EmployeeSerice { ArrayList<Employee> all; public EmployeeSerice() { all = new ArrayList<Employee>(); all.add(new Employee(1, "张三", '男', 33, 8000)); all.add(new Employee(2, "翠花", '女', 23, 18000)); all.add(new Employee(3, "无能", '男', 46, 8000)); all.add(new Employee(4, "李四", '女', 23, 9000)); all.add(new Employee(5, "老王", '男', 23, 15000)); all.add(new Employee(6, "大嘴", '男', 23, 11000)); } ArrayList<Employee> get(Predicate<Employee> p) { //在EmployeeSerice员工管理类中,声明一个方法: // ArrayList<Employee> get(Predicate<Employee> p), // 即将满足p指定的条件的员工,添加到一个新的ArrayList<Employee> 集合中返回。 ArrayList<Employee> emp = new ArrayList<>(); for (Employee employee : all) { //底层Predicate接口中有个抽象方法 boolean test(T t); 推断型接口返回类型为Boolean if (p.test(employee)) { emp.add(employee); } } return emp; } }
class EmployeeTest { public static void main(String[] args) { EmployeeSerice es = new EmployeeSerice(); /* es.get(new Predicate<Employee>() { @Override public boolean test(Employee employee) { System.out.println(employee); return true; } });*/ //- 所有员工对象 es.get((e)-> true).forEach((s) -> System.out.println(s)); System.out.println("-----------"); // - 所有年龄超过35的员工 es.get((e) -> e.getAge() > 35 ).forEach(System.out::println); // - 所有薪资高于15000的女员工 System.out.println("-------------------"); es.get((e) -> e.getSalary()>15000).forEach(System.out::println); // - 所有编号是偶数的员工 es.get((e) -> e.getId() % 2 == 0).forEach(System.out::println); // - 名字是“张三”的员工 es.get((e) -> e.getName().equals("张三")).forEach(System.out::println); // - 年龄超过25,薪资低于10000的男员工 es.get((e) -> e.getAge()>25 && e.getSalary()<10000).forEach(System.out::println); } }
这篇关于012—JAVA8新特性(lambda表达式)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-30java最新版本是什么,有什么特性?-icode9专业技术文章分享
- 2024-11-30[开源]27.8K star!这款 Postman 替代工具太火了!
- 2024-11-30Gzip 压缩入门教程:轻松掌握文件压缩技巧
- 2024-11-29开源工具的魅力:让文档管理更“聪明”
- 2024-11-29Release-it开发入门教程
- 2024-11-29Rollup 插件入门教程:轻松掌握模块打包
- 2024-11-29从零到一,产品经理如何玩转项目管理和团队协作
- 2024-11-29如何通过精益生产管理工具帮助项目团队实现精准进度控制?
- 2024-11-29低代码应用开发课程:新手入门与基础教程
- 2024-11-29入门指南:全栈低代码开发课程