1.lambda表达式

  1. 为什么要用lambda表达式,因为可以让代码更加简练

举例:以下是常见的开启线程的方式(采用了匿名内部类的方式)

  1. public static void main(String[] args) {
  2. //开启一个新的线程
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. // TODO Auto-generated method stub
  7. System.out.println("新线程执行"+Thread.currentThread().getName());
  8. }
  9. }).start();
  10. System.out.println("主线程执行"+Thread.currentThread().getName());
  11. }

代码分析:代码写得很长,比较复杂,用lambda表达式的方式可以让代码精简很多,以下就是lambda表达式的写法

  1. public static void main(String[] args) {
  2. //开启一个新的线程
  3. new Thread(() -> {System.out.println("开启一个新的lambda线程");}).start();
  4. System.out.println("主线程执行"+Thread.currentThread().getName());
  5. }

总结:简化了匿名内部类的使用,语法更加简单

  1. 使用前提:

方法的参数或者局部变量类型必须是接口
接口中有且仅有一个抽象方法

1、语法规则

(参数类型 参数名称)-> {代码体}
举例1:将main函数写法改成lambda方式

  1. public static void main(String[] args) {}
  1. (String[] args) -> {}

举例2:将以下的写法改成lambda表达式的方式

  1. public static void main(String[] args) {
  2. toUserService(new UserService() {
  3. @Override
  4. public void getName(String name) {
  5. System.out.println("你好"+name);
  6. return name;
  7. }
  8. });
  9. }
  10. public static void toUserService(UserService userService) {
  11. userService.getName("jf3q.com");
  12. }
  13. //UserServie接口如下
  14. public interface UserService {
  15. String getName(String name);
  16. }
  1. public static void main(String[] args) {
  2. toUserService((String name) -> {System.out.println("你好-"+name); return name;});
  3. }
  4. public static void toUserService(UserService userService) {
  5. userService.getName("jf3q.com");
  6. }
  7. public interface UserService {
  8. String getName(String name);
  9. }

核心代码部分:toUserService((String name) -> {System.out.println(“你好-“+name);return name;});

2、省略写法

  1. ()内的参数类型可以省略
  2. 如果()内有且仅有一个参数,则小括号也可以省略
  3. 如果{}内有且仅有一个语句,可以省略大括号,return关键字以及语句分号

练习:将toUserService((String name) -> {System.out.println(“你好-“+name);return name;});简化
toUserService(name -> {System.out.println(“你好-“+name);return name;});
分析:因为{}内有两个语句,所以不满足条件3.

3、lambda和匿名内部类的对比

  1. 所需类型不一样
    • 匿名内部类可以是类、抽象类、接口都行
    • lambda表达式需要的只能是接口
  2. 抽象方法的数量不一样
    • 匿名内部类所需接口中的抽象方法的数量是随意的
    • lambda表达式所需接口中 只能有一个抽象方法
  3. 实现原理不一样
    • 匿名内部类是在编译后形成一个class
    • lambda表达式是在程序运行的时候动态生成class

      2.接口中新增的方法

jdk8之前

  1. interface 接口name{
  2. 静态常量;
  3. 抽象方法;
  4. }

jdk8之后增加了默认方法静态方法

  1. interface 接口name{
  2. 静态常量;
  3. 抽象方法;
  4. 默认方法;
  5. 静态方法;
  6. }

1、默认方法

背景

在jdk8以前会存在问题:接口中新增抽象方法的话,那么实现该接口的所有类都得重写新的抽象方法,非常不利于接口的扩展。

  1. public class MoRenStudy {
  2. public static void main(String[] args) {
  3. A b=new B();
  4. A c=new C();
  5. }
  6. }
  7. interface A{
  8. void add();
  9. void delete();
  10. }
  11. class B implements A{
  12. @Override
  13. public void add() {
  14. System.out.println("B里的add方法调用");
  15. }
  16. @Override
  17. public void delete() {
  18. System.out.println("B里的delete方法调用");
  19. }
  20. }
  21. class C implements A{
  22. @Override
  23. public void add() {
  24. System.out.println("C里的add方法调用");
  25. }
  26. @Override
  27. public void delete() {
  28. System.out.println("C里的delete方法调用");
  29. }
  30. }

语法格式

  1. interface 接口name{
  2. 修饰符 default 返回值类型 方法名{
  3. 方法体;
  4. }
  5. }

使用案例:

  1. public class MoRenStudy {
  2. public static void main(String[] args) {
  3. A b=new B();
  4. b.delete();
  5. A c=new C();
  6. c.delete();
  7. }
  8. }
  9. interface A{
  10. void add();
  11. default void delete() {
  12. System.out.println("接口中的默认方法执行");
  13. };
  14. }
  15. class B implements A{
  16. @Override
  17. public void add() {
  18. System.out.println("B里的add方法调用");
  19. }
  20. @Override
  21. public void delete() {
  22. System.out.println("重写默认方法---B里的delete方法调用");
  23. }
  24. }
  25. class C implements A{
  26. @Override
  27. public void add() {
  28. System.out.println("C里的add方法调用");
  29. }
  30. }

代码分析:核心代码部分

  1. default void delete() {
  2. System.out.println("接口中的默认方法执行");
  3. };

打印出的结果就是:image.png
这就解决了那个问题——不用重写所有接口中的抽象方法(C实现类就没重写delete方法)

2.静态方法

语法规则

  1. interface 接口名{
  2. 修饰符 static 返回值类型 方法名(){
  3. 方法体
  4. }
  5. }

举例如下:

  1. public static void main(String[] args) {
  2. A a=new B();
  3. //调用静态方法
  4. A.delete();
  5. }
  6. }
  7. interface A{
  8. void add();
  9. public static void delete(){
  10. System.out.println("静态方法执行了");
  11. }
  12. }
  13. class B implements A{
  14. @Override
  15. public void add() {
  16. }
  17. //静态方法没法重写
  18. }

注意:接口中的静态方法是不能重写的,只能通过接口名.静态方法().

3.两者的区别

  1. 默认方法是通过实例调用,静态方法通过接口名调用
  2. 默认方法可以重写,静态方法不能重写

    3.函数式接口

    在jdk中提供了函数式接口的目的就是为了方便lambda表达式的。主要是在java.util.function包里
    常用的几个接口:

    1.Supplier(生产者-生产数据的)

    无参有返回值的接口,对应的lambda表达式需要提供一个返回数据的类型 ```java @FunctionalInterface public interface Supplier {

    /**

    • Gets a result. *
    • @return a result */ T get(); }
  1. 举例:求一个最大值的小案例
  2. 1. 匿名内部类的写法(最原始的写法)
  3. ```java
  4. //内部类的方法一
  5. public static void main(String[] args) {
  6. JsS jsS=new JsS();
  7. getMax(jsS);
  8. }
  9. public static void getMax(Js js){
  10. Integer max=js.jisuan();
  11. System.out.println("最大值"+max);
  12. }
  13. }
  14. interface Js{
  15. Integer jisuan();
  16. }
  17. class JsS implements Js{
  18. @Override
  19. public Integer jisuan() {
  20. Integer[] integers={3,2,6,9,10};
  21. Arrays.sort(integers);
  22. return integers[integers.length-1];
  23. }
  24. }
  1. //内部类方法二
  2. public static void main(String[] args) {
  3. getMax(new Js() {
  4. @Override
  5. public Integer jisuan() {
  6. Integer[] integers={3,2,6,9,10};
  7. Arrays.sort(integers);
  8. return integers[integers.length-1];
  9. }
  10. });
  11. }
  12. public static void getMax(Js js){
  13. Integer max=js.jisuan();
  14. System.out.println("最大值"+max);
  15. }
  16. }
  17. interface Js{
  18. Integer jisuan();
  19. }
  1. lambda表达式的写法 ```java public static void main(String[] args) {

    1. getMax(() -> {
    2. Integer[] integers={3,2,6,9,10};
    3. Arrays.sort(integers);
    4. return integers[integers.length-1];
    5. }
    6. );
  1. }
  2. public static void getMax(Js js){
  3. Integer max=js.jisuan();
  4. System.out.println("最大值"+max);
  5. }

} interface Js{ Integer jisuan(); }

  1. 3. 采用lambda表达式和supplier结合的方法
  2. ```java
  3. public static void main(String[] args) {
  4. getMax(() -> {
  5. Integer[] integers={3,2,6,9,10};
  6. Arrays.sort(integers);
  7. return integers[integers.length-1];
  8. }
  9. );
  10. }
  11. public static void getMax(Supplier<Integer> supplier){
  12. Integer max=supplier.get();
  13. System.out.println("最大值"+max);
  14. }
  15. }

2.Consumer(消费者)

有参无返回值的接口,使用的时候需要指定一个泛型来定义参数类型

  1. @FunctionalInterface
  2. public interface Consumer<T> {
  3. /**
  4. * Performs this operation on the given argument.
  5. *
  6. * @param t the input argument
  7. */
  8. void accept(T t);

举例说明:

  1. 还是求最大值

    1. public static void main(String[] args) {
    2. getMax((max) -> {
    3. System.out.println(max);
    4. }
    5. );
    6. }
    7. public static void getMax(Consumer<Integer> consumer){
    8. Integer[] integers={3,2,6,9,10};
    9. Arrays.sort(integers);
    10. consumer.accept(integers[integers.length-1]);
    11. }
  2. 大写转小写

    1. public static void main(String[] args) {
    2. zhuan((str) -> {
    3. System.out.println(str+"转成全小写"+str.toLowerCase());
    4. }
    5. );
    6. }
    7. public static void zhuan(Consumer<String> consumer){
    8. consumer.accept("Hello word");
    9. }

    3.Function

    有参有返回值的接口 ```java @FunctionalInterface public interface Function {

    /**

    • Applies this function to the given argument. *
    • @param t the function argument
    • @return the function result */ R apply(T t);
  1. <a name="OVfi9"></a>
  2. ## 4.Predicate
  3. 有参且返回值是boolean类型的接口
  4. ```java
  5. @FunctionalInterface
  6. public interface Predicate<T> {
  7. /**
  8. * Evaluates this predicate on the given argument.
  9. *
  10. * @param t the input argument
  11. * @return {@code true} if the input argument matches the predicate,
  12. * otherwise {@code false}
  13. */
  14. boolean test(T t);