2020了你还不会Java8新特性?Lambda表达式及API(二)
lambda表达式
为什么要使用lambda表示式
- 在Java中无法将函数座位参数传递给一个方法,也无法返回一个函数的方法。
- 在js中,函数的参数是一个函数。返回值是另一个函数的情况是非常常见的。是一门经典的函数式语言。
Java匿名内部类。
匿名内部类的介绍
Gradle的使用。可以完全使用maven的中央仓库。
进行安卓的开发时,gradle已经成为标配了。
lambda:
匿名内部类
my_jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button Pressed! "); } });
改造后
my_jButton.addActionListener(e -> System.out.println("Button Pressed!"));
lambda表达式的基本结构:
(param1,param2,param3) ->{ }
函数式编程: 一个接口里边只有一个抽象方法。
可以通过lambda表达式来实例。
关于函数式接口:
- 如果一个借口只有一个抽象方法,那么该接口就是一个函数式接口。
- 如果我们在某一个接口上声明了functionalInterface注解,那么编译器就会按照函数是借口的定义来要求改接口。
- 如果某个接口只有一个抽象方法,但是我们并没有给接口声明functionnaleInterface注解,编译器依旧会给改接口看作是函数式接口。
通过实例对函数式接口的理解:
package com.erwa.jdk8; @FunctionalInterface interface MyInterface { void test(); // Multiple non-overriding abstract methods found in interface com.erwa.jdk8.MyInterface // void te(); //如果一个接口声明一个抽象方法,但是这个方法重写了 object类中的一个方法. //接口的抽象方法不会加一.所以依然是函数方法. // Object 类是所有类的父类. @Override String toString(); } public class Test2 { public void myTest(MyInterface myInterface) { System.out.println(1); myInterface.test(); System.out.println(2); } public static void main(String[] args) { Test2 test2 = new Test2(); test2.myTest(() -> { System.out.println(3); }); } }
接口里边从1.8开始也可以有方法实现了。default
默认方法。 default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
* <p>Note that instances of functional interfaces can be created with * lambda expressions, method references, or constructor reference
lambda表达式的作用:
- lambda表达式为Java添加了确实的函数式编程特性,使我们能将函数当做一等公民看待。
- 在将函数座位一等公民的语言中,lambda表达式的类型是函数。但是在Java中,lambda表达式是对象,他们必须依附于一类特别的对象类型-函数式接口(function interface)
迭代的方式:
- 外部迭代:
- 内部迭代:
- 方法引用:
list.forEach(System.out::println);
接口中可以有默认方法和静态方法。
流: stream
/** * Returns a sequential {@code Stream} with this collection as its source. * * <p>This method should be overridden when the {@link #spliterator()} * method cannot return a spliterator that is {@code IMMUTABLE}, * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()} * for details.) * * @implSpec * The default implementation creates a sequential {@code Stream} from the * collection's {@code Spliterator}. * * @return a sequential {@code Stream} over the elements in this collection * @since 1.8 */ default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
关于流方式实现的举例:
public static void main(String[] args) { //函数式接口的实现方式 MyInterface1 i1 = () -> {}; System.out.println(i1.getClass().getInterfaces()[0]); MyInterface2 i2 = () -> {}; System.out.println(i2.getClass().getInterfaces()[0]); // 没有上下文对象,一定会报错的. // () -> {}; //通过lambda来实现一个线程. new Thread(() -> System.out.println("hello world")).start(); //有一个list ,将内容中的首字母变大写输出. List<String> list = Arrays.asList("hello","world","hello world"); //通过lambda来实现所有字母编程大写输出. // list.forEach(item -> System.out.println(item.toUpperCase())); //把三个单词放入到新的集合里边. List<String> list1 = new ArrayList<>(); //diamond语法. 后边的<>不用再放类型 // list.forEach(item -> list1.add(item.toUpperCase())); // list1.forEach(System.out::println); //进一步的改进. 流的方式 // list.stream();//单线程 // list.parallelStream(); //多线程 list.stream().map(item -> item.toUpperCase()).forEach(System.out::println);//单线程 list.stream().map(String::toUpperCase).forEach(System.out::println); //上边的两种方法,都满足函数式接口的方式. }
lambda表达式的作
- 传递行为,而不仅仅是值
- 提升抽象层次
- API重用性更好
- 更加灵活
lambda基本语法
- (argument) -> (body)
- 如: (arg1,arg2...) -> (body)
Java lambda结构
- 一个Lambda表达式可以有0个或者多个参数
- 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a) 与 (a) 效果相同
- 所有参数包含在圆括号内,参数之间用逗号相隔。
- 空圆括号代表参数集为空。
- 当只有一个参数,且类型可推倒时。圆括号()可省略。
- lambda表达式的主体可以包含0条或多条语句。
- 如果lambda表达式的主体只有一条语句,花括号{}可以省略,匿名函数的返回类型与该主体表达式一致。
- 如果lambda表达式的主体包含一条以上语句,则表达式必须包含在花括号中。匿名函数的韩绘制类型与代码块的返回类型一致,诺没有反回则为空。
高阶函数:
如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数.
传递行为的举例:
public static void main(String[] args) { // 函数的测试 // 传递行为的一种方式. FunctionTest functionTest = new FunctionTest(); int compute = functionTest.compute(1, value -> 2 * value); System.out.println(compute); System.out.println(functionTest.compute(2,value -> 5+ value)); System.out.println(functionTest.compute(3,a -> a * a)); System.out.println(functionTest.convert(5, a -> a + "hello ")); /** * 高阶函数: * 如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数. */ } //使用lambda表达式的话,可以直觉预定义行为.用的时候传递. // 即 函数式编程. public int compute(int a, Function<Integer, Integer> function) { return function.apply(a); } public String convert(int a, Function<Integer, String> function) { return function.apply(a); } // 之前完成行为的做法. 提前把行为定义好,用的时候调用方法. 如: public int method1(int a ){ return a * 2 ; }
Function类中提供的默认方法的讲解:
/** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. 返回一个组合的函数。对应用完参数后的结果,再次运行apply * * @param <V> the type of input to the {@code before} function, and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function, and of the * composed function * @param after the function to apply after this function is applied * @return a composed function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null * * @see #compose(Function) */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
compose : 组合function, 形成两个function的串联。 先执行参数
andThen :先应用当前的函数apply,然后再当做参数再次执行apply。 后执行参数。
identity:输入什么返回什么。
BiFunction: 整合两个函数的方法。
为什么BiFunction不提供 compose ,只提供andThen呢?
因为如果提供compose方法的话,只能获取一个参数的返回值。不合理。
public static void main(String[] args) { FunctionTest2 functionTest2 = new FunctionTest2(); // compose // System.out.println(functionTest2.compute(2,a -> a * 3,b -> b * b)); // andThen // System.out.println(functionTest2.compute2(2,a -> a * 3,b -> b * b)); //BiFunction // System.out.println(functionTest2.compute3(1,2, (a,b) -> a - b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a * b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a + b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a / b)); //BiFunction andThen System.out.println(functionTest2.compute4(2,3,(a,b) ->a + b , a -> a * a )); } //compose : 组合function, 形成两个function的串联。 先执行参数 //andThen :先应用当前的函数apply,然后再当做参数再次执行apply。 后执行参数 public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.compose(function2).apply(a); } public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.andThen(function2).apply(a); } //BiFunction //求两个参数的和 //先定义一个抽象的行为. public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) { return biFunction.apply(a, b); } //BiFunction andThen public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) { return biFunction.andThen(function).apply(a, b); }
测试 函数式接口的实例:
public class PersonTest { public static void main(String[] args) { List<Person> personList = new ArrayList<>(); personList.add(new Person("zhangsan", 20)); personList.add(new Person("zhangsan", 28)); personList.add(new Person("lisi", 30)); personList.add(new Person("wangwu", 40)); PersonTest test = new PersonTest(); //测试 getPersonUsername // List<Person> personList1 = test.getPersonUsername("zhangsan", personList); // personList1.forEach(person -> System.out.println(person.getUsername())); //测试 getPersonByAge List<Person> personByAge = test.getPersonByAge(25, personList); personByAge.forEach(person -> System.out.println(person.getAge())); //测试第三种: 自定义输入行为 List<Person> list = test.getPersonByAge2(20,personList,(age,persons) ->{ return persons.stream().filter(person -> person.getAge() > age).collect(Collectors.toList()); }); list.forEach(person -> System.out.println(person.getAge())); } public List<Person> getPersonUsername(String username, List<Person> personList) { return personList.stream().filter(person -> person.getUsername().equals(username)).collect(Collectors.toList()); } public List<Person> getPersonByAge(int age, List<Person> personList) { //使用BiFunction的方式 // BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> { // return list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList()); // }; //变换之后: BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList()); return biFunction.apply(age, personList); } //第三种方式, 动作也让用户自己定义传进来 public List<Person> getPersonByAge2(int age ,List<Person> list,BiFunction<Integer,List<Person>,List<Person>> biFunction){ return biFunction.apply(age, list); } }
函数式接口的真谛: 传递的是行为,而不是数据
。
public static void main(String[] args) { //给定一个输入参数,判断是否满足条件,满足的话返回true Predicate<String> predicate = p -> p.length() > 5; System.out.println(predicate.test("nnihaoda")); }
到现在为止,只是讲解了Java.lang.function包下的几个最重要的,经常使用的方法。
2020年1月3日08:06:28
BinaryOperator 接口
public class SinaryOpertorTest { public static void main(String[] args) { SinaryOpertorTest sinaryOpertorTest = new SinaryOpertorTest(); System.out.println(sinaryOpertorTest.compute(1,2,(a,b) -> a+b)); System.out.println("-- -- - - - -- -"); System.out.println(sinaryOpertorTest.getMax("hello123","world",(a,b) -> a.length() - b.length())); } private int compute(int a, int b, BinaryOperator<Integer> binaryOperator) { return binaryOperator.apply(a, b); } private String getMax(String a, String b, Comparator<String> comparator) { return BinaryOperator.maxBy(comparator).apply(a, b); } }
Optional final :Optional 不要试图用来当做参数, 一般只用来接收返回值,来规避值的空指针异常的问题。
- empty()
- of()
- ofNullable()
- isPresent()
- get()
- ...
public class OptionalTest { public static void main(String[] args) { Optional<String> optional = Optional.of("hello"); //不确定是否为 空是 调用和这个方法 // Optional<String> optional2 = Optional.ofNullable("hello"); // Optional<String> optional1 = Optional.empty(); //过时 // if (optional.isPresent()) { // System.out.println(optional.get()); // } optional.ifPresent(item -> System.out.println(item)); System.out.println(optional.orElse("nihao")); System.out.println(optional.orElseGet(() -> "nihao")); }
public class OptionalTest2 { public static void main(String[] args) { Employee employee = new Employee(); employee.setName("dawa"); Employee employee1 = new Employee(); employee1.setName("erwa"); List<Employee> list = Arrays.asList(employee, employee1); Company company = new Company("gongsi", list); Optional<Company> optionalCompany = Optional.ofNullable(company); System.out.println(optionalCompany.map(company1 -> company1.getList()).orElse(Collections.emptyList())); } }
相关推荐
f = lambda x, y, z: x + y + z # returns a function that can optionally be assigned a name. def func: