赞
踩
冗余的匿名内部类:
当需要启动一个线程去完成任务时,通常会通过java.lang.Runnable
接口来定义任务内容,并使用java.lang.Thread
类来启动该线程。代码如下:
package com.atguigu.fp;
public class UseFunctionalProgramming {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行!");
}
}).start(); // 启动线程
}
}
本着“一切皆对象”的思想,这种做法是无可厚非的:首先创建一个Runnable
接口的匿名内部类对象来指定任务内容,再将其交给一个线程来启动
代码分析:
对于Runnable
的匿名内部类用法,可以分析出几点内容:
Thread
类需要Runnable
接口作为参数,其中的抽象run
方法是用来指定线程任务内容的核心;run
的方法体,不得不需要Runnable
接口的实现类;RunnableImpl
实现类的麻烦,不得不使用匿名内部类;run
方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;Lambda 操作符或
箭头操作符`。它将 Lambda 分为两个部分:
**语法格式一:**无参,无返回值
@Test public void test1(){ //未使用Lambda表达式 Runnable r1 = new Runnable() { @Override public void run() { System.out.println("我爱北京天安门"); } }; r1.run(); System.out.println("***********************"); //使用Lambda表达式 Runnable r2 = () -> { System.out.println("我爱北京故宫"); }; r2.run(); }
语法格式二:Lambda 需要一个参数,但是没有返回值。
@Test public void test2(){ //未使用Lambda表达式 Consumer<String> con = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con.accept("谎言和誓言的区别是什么?"); System.out.println("*******************"); //使用Lambda表达式 Consumer<String> con1 = (String s) -> { System.out.println(s); }; con1.accept("一个是听得人当真了,一个是说的人当真了"); }
语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test public void test3(){ //语法格式三使用前 Consumer<String> con1 = (String s) -> { System.out.println(s); }; con1.accept("一个是听得人当真了,一个是说的人当真了"); System.out.println("*******************"); //语法格式三使用后 Consumer<String> con2 = (s) -> { System.out.println(s); }; con2.accept("一个是听得人当真了,一个是说的人当真了"); }
语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
@Test public void test4(){ //语法格式四使用前 Consumer<String> con1 = (s) -> { System.out.println(s); }; con1.accept("一个是听得人当真了,一个是说的人当真了"); System.out.println("*******************"); //语法格式四使用后 Consumer<String> con2 = s -> { System.out.println(s); }; con2.accept("一个是听得人当真了,一个是说的人当真了"); }
语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test public void test5(){ //语法格式五使用前 Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; System.out.println(com1.compare(12,21)); System.out.println("*****************************"); //语法格式五使用后 Comparator<Integer> com2 = (o1,o2) -> { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); }; System.out.println(com2.compare(12,6)); }
语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
@Test public void test6(){ //语法格式六使用前 Comparator<Integer> com1 = (o1,o2) -> { return o1.compareTo(o2); }; System.out.println(com1.compare(12,6)); System.out.println("*****************************"); //语法格式六使用后 Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2); System.out.println(com2.compare(12,21)); } @Test public void test7(){ //语法格式六使用前 Consumer<String> con1 = s -> { System.out.println(s); }; con1.accept("一个是听得人当真了,一个是说的人当真了"); System.out.println("*****************************"); //语法格式六使用后 Consumer<String> con2 = s -> System.out.println(s); con2.accept("一个是听得人当真了,一个是说的人当真了"); }
一个抽象方法
的接口,称为函数式接口。当然该接口可以包含其他非抽象方法。@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。之前学过的接口,有些就是函数式接口,比如:
练习
练习1:无参无返回值形式
public class TestLambda {
public static void main(String[] args) {
callSomething(()->System.out.println("回家吃饭"));
callSomething(()->System.out.println("我爱你"));
callSomething(()->System.out.println("滚蛋"));
callSomething(()->System.out.println("回来"));
}
public static void callSomething(Call call){
call.shout();
}
}
interface Call {
void shout();
}
练习2:消费型接口
代码示例:Consumer接口
在JDK1.8中Collection集合接口的父接口Iterable接口中增加了一个默认方法:
public default void forEach(Consumer<? super T> action)
遍历Collection集合的每个元素,执行“xxx消费型”操作。
在JDK1.8中Map集合接口中增加了一个默认方法:
public default void forEach(BiConsumer<? super K,? super V> action)
遍历Map集合的每对映射关系,执行“xxx消费型”操作。
案例:
(1)创建一个Collection系列的集合,添加一些字符串,调用forEach方法遍历查看
(2)创建一个Map系列的集合,添加一些(key,value)键值对,调用forEach方法遍历查看
示例代码:
@Test
public void test1(){
List<String> list = Arrays.asList("hello","java","lambda","atguigu");
list.forEach(s -> System.out.println(s));
}
@Test
public void test2(){
HashMap<Integer,String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "java");
map.put(3, "lambda");
map.put(4, "atguigu");
map.forEach((k,v) -> System.out.println(k+"->"+v));
}
练习3:供给型接口
现在请调用Stream的generate方法,来产生一个流对象,并调用Math.random()方法来产生数据,为Supplier函数式接口的形参赋值。最后调用forEach方法遍历流中的数据查看结果。
@Test
public void test2(){
Stream.generate(() -> Math.random()).forEach(num -> System.out.println(num));
}
练习4:功能型接口
代码示例:Function<T,R>接口
在JDK1.8时Map接口增加了很多方法,例如:
public default void replaceAll(BiFunction<? super K,? super V,? extends V> function)
按照function指定的操作替换map中的value。
public default void forEach(BiConsumer<? super K,? super V> action)
遍历Map集合的每对映射关系,执行“xxx消费型”操作。
案例:
(1)声明一个Employee员工类型,包含编号、姓名、薪资。
(2)添加n个员工对象到一个HashMap<Integer,Employee>集合中,其中员工编号为key,员工对象为value。
(3)调用Map的forEach遍历集合
(4)调用Map的replaceAll方法,将其中薪资低于10000元的,薪资设置为10000。
(5)再次调用Map的forEach遍历集合查看结果
enployee类代码:
class Employee{ private int id; private String name; private double salary; public Employee(int id, String name, double salary) { super(); this.id = id; this.name = name; 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 double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]"; } }
测试类:
import java.util.HashMap; public class TestLambda { public static void main(String[] args) { HashMap<Integer,Employee> map = new HashMap<>(); Employee e1 = new Employee(1, "张三", 8000); Employee e2 = new Employee(2, "李四", 9000); Employee e3 = new Employee(3, "王五", 10000); Employee e4 = new Employee(4, "赵六", 11000); Employee e5 = new Employee(5, "钱七", 12000); map.put(e1.getId(), e1); map.put(e2.getId(), e2); map.put(e3.getId(), e3); map.put(e4.getId(), e4); map.put(e5.getId(), e5); map.forEach((k,v) -> System.out.println(k+"="+v)); System.out.println(); map.replaceAll((k,v)->{ if(v.getSalary()<10000){ v.setSalary(10000); } return v; }); map.forEach((k,v) -> System.out.println(k+"="+v)); } }
练习5:判断型接口
代码示例:Predicate接口
JDK1.8时,Collecton接口增加了一下方法,其中一个如下:
public default boolean removeIf(Predicate<? super E> filter)
用于删除集合中满足filter指定的条件判断的。
public default void forEach(Consumer<? super T> action)
遍历Collection集合的每个元素,执行“xxx消费型”操作。
案例:
(1)添加一些字符串到一个Collection集合中
(2)调用forEach遍历集合
(3)调用removeIf方法,删除其中字符串的长度<5的
(4)再次调用forEach遍历集合
import java.util.ArrayList; public class TestLambda { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("hello"); list.add("java"); list.add("atguigu"); list.add("ok"); list.add("yes"); list.forEach(str->System.out.println(str)); System.out.println(); list.removeIf(str->str.length()<5); list.forEach(str->System.out.println(str)); } }
练习6:判断型接口
案例:
(1)声明一个Employee员工类型,包含编号、姓名、性别,年龄,薪资。
(2)声明一个EmployeeSerice员工管理类,包含一个ArrayList集合的属性all,在EmployeeSerice的构造器中,创建一些员工对象,为all集合初始化。
(3)在EmployeeSerice员工管理类中,声明一个方法:ArrayList get(Predicate p),即将满足p指定的条件的员工,添加到一个新的ArrayList 集合中返回。
(4)在测试类中创建EmployeeSerice员工管理类的对象,并调用get方法,分别获取:
示例代码:
Employee类:
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 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 + "]"; } }
员工管理类:
class EmployeeService{ private ArrayList<Employee> all; public EmployeeService(){ 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)); } public ArrayList<Employee> get(Predicate<Employee> p){ ArrayList<Employee> result = new ArrayList<Employee>(); for (Employee emp : result) { if(p.test(emp)){ result.add(emp); } } return result; } }
测试类:
public class TestLambda { public static void main(String[] args) { EmployeeService es = new EmployeeService(); es.get(e -> true).forEach(e->System.out.println(e)); System.out.println(); es.get(e -> e.getAge()>35).forEach(e->System.out.println(e)); System.out.println(); es.get(e -> e.getSalary()>15000 && e.getGender()=='女').forEach(e->System.out.println(e)); System.out.println(); es.get(e -> e.getId()%2==0).forEach(e->System.out.println(e)); System.out.println(); es.get(e -> "张三".equals(e.getName())).forEach(e->System.out.println(e)); System.out.println(); es.get(e -> e.getAge()>25 && e.getSalary()<10000 && e.getGender()=='男').forEach(e->System.out.println(e)); } } - 所有员工对象 - 所有年龄超过35的员工 - 所有薪资高于15000的女员工 - 所有编号是偶数的员工 - 名字是“张三”的员工 - 年龄超过25,薪资低于10000的男员工
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。