2020了你还不会Java8新特性?Lambda表达式及API
Posted wobushitiegan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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()));
}
}
以上是关于2020了你还不会Java8新特性?Lambda表达式及API的主要内容,如果未能解决你的问题,请参考以下文章
2020了你还不会Java8新特性?时间日期API&&Java8总结
2020了你还不会Java8新特性?Collector类源码分析
2020了你还不会Java8新特性?收集器比较器用法详解及源码剖析
Java8新特性,你一定能学会的超详细保姆级源码笔记,看完还不会请直接砍我