Lambda表达式

Java8新特性-Lambda表达式

Lambda表达式

简介

Lambda表达式(也称闭包),是Java8中最受期待和欢迎的新特性之一。Lambda表达式本质是一个匿名函数,但是它并不是匿名类的语法糖,它让 Java 开始走向函数式编程,其实现原理区别于一般的匿名类中的匿名函数。在Java语法层面Lambda表达式允许函数作为一个方法的参数(函数作为参数传递到方法中),或者把代码看成数据。Lambda表达式可以简化函数式接口的使用。函数式接口就是一个只有一个抽象方法的普通接口像这样的接口就可以使用Lambda表达式来简化代码的编写。

语法糖是什么?

语法糖,又称糖衣语法,是英国计算机科学家发明的一个术语,指在计算机语言中加入某种语法,这种语法对语言的功能并没有影响,但是方便了程序员的操作,并且增加了代码的可读性,减少了出错的机会。

Java 是一个 “低糖语言”,因为在 JDK1.5 之前,语法糖很少出现。但是从 Java 7 开始 Java 语言层面上一直在添加各种糖,未来还会持续向着 “高糖” 的方向发展。

Java 中最常用的语法糖主要有泛型、switch 支持 String、自动装箱与拆箱、foreach 循环、内部类和枚举等。

解语法糖

语法糖主要是方便开发人员使用。但其实,Java 虚拟机并不支持这些语法糖,这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖

举例:

public class Test {
	public static void main(String[] args) {
		String str = "world"; 
		switch (str) {
		case "hello": 
			System.out.println("hello"); 
			break;
		case "world": 
			System.out.println("world");
			break;
		default:
			break;
		}
	}
}
//反编译之后
public class Test {
	public static void main(String args[]){
		String str = "world";
		String s;
		switch((s = str).hashCode()){
		default:
			break;
		case 99162322:
			if(s.equals("hello"))
				System.out.println("hello");
			break;
		case 113318802:
			if(s.equals("world"))
				System.out.println("world");
			break;
		}
	}
}

优点和缺点

Lambda表达式的目的:当一个接口中,只有一个抽象方法,那么匿名内部类的语法就会显的十分的笨拙,产生大量的代码,总结一句就是:代码冗余就是匿名内部类最大的弊端。在编写代码的时候,我们很多时候希望把功能作为参数传递到另一个方法当中,Lambda表达式就是为此而生。

优点:

  • 使用Lambda表达式可以简化接口匿名内部类的代码,可以减少类文件的生成,同时引入了强大的类型推断和方法引用特性,简单的功能甚至可以一行代码解决,解放匿名类的束缚。
  • 把功能作为参数向下传递,为函数式编程提供了支持,让 Java 开始走向函数式编程。

缺点

  • 使用Lambda表达式会减弱代码的可读性,而且Lambda表达式的使用局限性比较强,只能适用于接口只有一个抽象方法时使用,不方便调试。

下面我们来说一下Lambda表达式的基本概念

函数式接口

函数式接口的概念
  • 有且只有一个抽象方法的接口被为函数式接口
  • 只有函数式接口,才可以转换为lambda表达式
  • 接口默认方法必须予以实现,它们不是抽象方法(默认方法将在下面会讲到)
  • 们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
理解函数式接口
  • Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即**java不但可以支持OOP还可以支持OOF(面向函数编程) **
  • 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。
  • 简单的说,在Java8中,**Lambda表达式就是一个函数式接口的实例。**这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
  • 以前用匿名实现类表示的现在都可以用Lambda表达式来写。
例子

Runnabale线程接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface {@code Runnable} is used
     * to create a thread, starting the thread causes the object's
     * {@code run} method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method {@code run} is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

自定义函数式接口

package com.song.Lambda.Server;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/7 20:28
 * @Description TODO
 */
@FunctionalInterface // 这个可以不带 但是写上这个注解更直观
public interface MyFunction<T> {
    T getValue(T value);
}

Java8内置的函数接口

四大核心接口

接口参数返回值
Consumer<T>消费型接口Tvoid
Supplier<T>供给型接口T
Function<T,R>函数型接口TR
Predicate<T>断定型接口Tboolean
UnaryOperator<T>一元操作符TT
BinaryOperator<T>二元操作符T,TT

消费性接口

Consumer 接口只有一个抽象方法 accept,参数列表只有一个泛型t,无返回值,重点在于内部消费

package com.song.inFunction;

import java.util.function.Consumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 11:16
 * @Description TODO
 */

// Consumer 就像一个消费者,它只消费一个东西(也就是一个对象),并不返回状态,
public class ConsumerDemo01 {
    public static void main(String[] args) {
        Consumer<String> consumer=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("Consumer消费型接口");
    }
}

如果需要多个参数列表的话,可以考虑使用 ObjLongConsumer

ObjLongConsumer<String> objLongConsumer=new ObjLongConsumer<String>() {
            @Override
            public void accept(String s, long value) {
                System.out.println(s+value);      
            }
        };
        objLongConsumer.accept("1",2);

供给型接口

Supplier 只有一个抽象方法 get,参数列表为空,有返回值,返回值得数据类型为T。

package com.song.inFunction;

import java.util.function.Supplier;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 11:26
 * @Description TODO
 */
// 是一个对象提供器,但是它不需要参数就可以生成一个对象
public class SupplierDemo01 {
    public static void main(String[] args) {
        Supplier<String> supplier=new Supplier<String>() {
            @Override
            public String get() {
                return "132";
            }
        };
        String s = supplier.get();
        System.out.println(s);
    }
}

如果需要返回得数据为基本数据类型,可以考虑使用 LongSupplier

LongSupplier longSupplier=new LongSupplier() {
            @Override
            public long getAsLong() {
                return 1;
            }
        };

函数型接口

Function<T, R> 只有一个抽象方法名为 apply,参数列表只有一个参数为T,有返回值,返回值的数据类型为R。

package com.song.inFunction;

import java.util.function.Function;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 11:30
 * @Description TODO
 */
// 就是数学中的函数,例如 g=f(x),因此它是通过一个参数生成一个值,
public class FunctionDemo01 {
    public static void main(String[] args) {
        Function<String,Integer> function=new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.valueOf(s);
            }
        };
        System.out.println(function.apply("123"));

    }
}

如果需要多个入参,然后又返回值的话,可以考虑 BiFunction

断言型接口

断言型又名判断型。 Predicate 只有一个抽象方法 test,参数列表只有一个参数为 T,有返回值,返回值类型为 boolean。

package com.song.inFunction;

import java.util.function.Predicate;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 14:35
 * @Description TODO
 */
public class PredicateDemo01 {
    public static void main(String[] args) {
        Predicate<String> predicate=new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s!=null;
            }
        };
        predicate.test(null);
    }
}

注意点
  • 该注解只能标记在"有且仅有一个抽象方法"的接口上。

  • JDK8接口中的静态方法和默认方法,都不算是抽象方法。

  • 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。

  • 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

  • 如果一个接口中包含不止一个抽象方法,那么不能使用@FunctionalInterface,编译会报错。

接口中的默认方法与静态方法

Java8之前的接口中只能定义全局常量,抽象方法,

Java8之后的接口中能定义全局常量,抽象方法,默认方法以及静态方法

默认方法

接口默认方法(下称默认方法)通过default关键字声明,可以直接在接口中编写方法体。也就是默认方法既声明了方法,也实现了方法

package com.song.DefaultMethod;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/7 23:14
 * @Description TODO
 */
public interface Demo01<T> {
    T get();

    default String getName(){
        return "hello Java8!";
    }
}

接口中的默认方接口默认方法的”类优先”原则

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时

  • (情况一)选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略(父类与接口中定义了相同的名称的方法,默认实现父类的)
  • **(情况二)**接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

如果继承一个定义了默认方法的接口,那么可以有如下的做法:

  • 完全忽略父接口的默认方法,那么相当于直接继承父接口的默认方法的实现(方法继承)。

  • 重新声明默认方法,这里特指去掉default关键字,用public abstract关键字重新声明对应的方法,相当于让默认方法转变为抽象方法,子类需要进行实现(方法抽象)。

  • 重新定义默认方法,也就是直接覆盖父接口中的实现(方法覆盖)。

结合前面一节提到的函数式接口,这里可以综合得出一个结论:函数式接口,也就是有且仅有一个抽象方法的接口,可以定义0个或者N(N >= 1)个默认方法

静态方法

Java8 中,接口中允许添加静态方法。

package com.song.DefaultMethod;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/7 23:22
 * @Description TODO
 */
public interface Demo02 {
    Integer myFun();
    default String getName(){
        return "hello";
    }
    static void show(){
        System.out.println("hello Java8");
    }
}

使用Lambd表达式的前提

只适用于函数式接口,即接口有且只有一个抽象方法!!!

基础语法

在认识Lambda表达式基础语法之前,先来看一段用两种方式创建线程的代码

package com.song.LambdaDemo;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:02
 * @Description TODO
 */
public class LambdaDemo01 {
    public static void main(String[] args) {
        // 普通的写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"run");     
            }
        }).start();
        
        // Lambda 简化写法
        new Thread(() ->{
            System.out.println(Thread.currentThread().getName()+"run");
        }).start();
        
    }
}

在这里插入图片描述

Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符箭头操作符。它将 Lambda 分为两个部分:

左侧:指定了 Lambda 表达式需要的参数列表 (其实就是接口中的抽象方法的形参列表)

右侧:指定了 Lambda 体,是抽象方法的实现逻辑(其实就是重写的抽象方法的方法体)

Lambda表达式重要的特征

可选参数类型声明

不需要声明参数类型,编译器可以统一识别参数值。 称为“类型推断”

package com.song.LambdaDemo;

import java.util.function.Consumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:17
 * @Description TODO
 */
public class LambdaDemo02 {
    public static void main(String[] args) {
        Consumer<String> c1= (String s) -> {
            System.out.println(s);
        };
        c1.accept("222");

        Consumer<String> c2=(s) ->{
            System.out.println(s);
        };
        c2.accept("333");
    }
}

可选的参数圆括号

一个参数无需定义圆括号,但多个参数需要定义圆括号。例如:

package com.song.LambdaDemo;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:19
 * @Description TODO
 */
public class LambdaDemo03 {
    public static void main(String[] args) {
        Consumer<String> c1= s ->{
            System.out.println(s);
        };
        c1.accept("111");

        Comparator<String> comparator= (s1,s2) -> {
            int i = s1.compareTo(s2);
            return i;
        };
        comparator.compare("111","222");
    }
}

可选的Lambda体大括号
package com.song.LambdaDemo;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:22
 * @Description TODO
 */
public class LambdaDemo04 {
    public static void main(String[] args) {
        Consumer<String> consumer= s -> System.out.println(s);

        consumer.accept("111");

        Comparator<String> comparator= (s1, s2) -> {
            int i = s1.compareTo(s2);
            return i;
        };
        comparator.compare("111","222");
    }
}

可选的返回关键字

如果Lambda体不加{ }就不用写return,Lambda体加上{ }就需要添加return。

package com.song.LambdaDemo;

import java.util.Comparator;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:23
 * @Description TODO
 */
public class LambdaDemo05 {
    public static void main(String[] args) {
        Comparator<Integer> comparator1= (i1,i2) ->{
            int i = i1.compareTo(i2);
            return  i;
        };

        System.out.println(comparator1.compare(4, 5));

        Comparator<Integer> comparator2 = (o1,o2) -> o1.compareTo(o2);

        System.out.println(comparator2.compare(2, 3));
    }
}

目标类型与类型推断

目标类型
package com.song.LambdaDemo;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 15:42
 * @Description TODO
 */
@FunctionalInterface
public interface Runnable {
    void  run();

    static void main(String[] args) {
        java.lang.Runnable runnable1= ()-> System.out.println(111);
        com.song.LambdaDemo.Runnable runnable2 =() -> System.out.println(333);
        
        runnable1.run();
        runnable2.run();
    }
}

定义了一个和java.lang.Runnable完全一致的函数式接口com.song.LambdaDemo.Runnable,上面main()方法中,可以看到两个接口对应的Lambda表达式的方法体实现也是完全一致,但是很明显最终可以使用不同类型的接口去接收返回值,也就是这两个Lambda的类型是不相同的。而这两个Lambda表达式返回值的类型是我们最终期待的返回值类型(expecting a data type of XX),那么Lambda表达式就是对应的被期待的类型,这个被期待的类型就是Lambda表达式的目标类型

为了确定Lambda表达式的目标类型,Java编译器会基于对应的Lambda表达式,使用上下文或者场景进行综合推导,判断的一个因素就是上下文中对该Lambda表达式所期待的类型。因此,只能在Java编译器能够正确推断Lambda表达式目标类型的场景下才能使用Lambda表达式,这些场景包括:

  • 变量声明。
  • 赋值。
  • 返回语句。
  • 数组初始化器。
  • Lambda表达式函数体。
  • 条件表达式(condition ? processIfTrue() : processIfFalse())。
  • 类型转换(Cast)表达式。

Lambda表达式除了目标类型,还包含参数列表和方法体,而方法体需要依赖于参数列表进行实现,所以方法参数也是决定目标类型的一个因素

方法引用

方法引用的概念

方法引用(Method Reference)是用来直接访问类或者实例已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。

方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

作用

  • 方法引用的唯一用途是支持Lambda的简写。
  • 方法引用提高了代码的可读性,也使逻辑更加清晰。
语法

使用::操作符将方法名和对象或类的名字分隔开。::是域操作符(也可以称作定界符、分隔符)。

常见的方法引用

常见的方法引用

方法引用等价的Lambda表达式
String::valueOfx -> String.valueOf(x)
Object::toStringx -> x.toString()
x::toString() -> x.toString()
ArrayList::new() -> new ArrayList<>()

方法引用的类型归结如下:

类型例子
静态方法引用 类::静态方法名ClassName::methodName
指定对象实例方法引用 对象::实例方法名instanceRef::methodName
特定类型任意对象方法引用 类::实例方法名ContainingType::methodName
超类方法引用supper::methodName
构造器方法引用ClassName::new
数组构造器方法引用TypeName[]::new

可见其基本形式是:方法容器::方法名称或者关键字

静态方法的引用
package com.song.LambdaDemo;

import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 16:46
 * @Description TODO
 */
public class StaticReference {
    public static void main(String[] args) {
        // 匿名内部类形式全写形式
        Function<String,Integer> f1= new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.valueOf(s);
            }
        };

        // Lambda表达式形式
        Function<String,Integer> f2 = s -> Integer.valueOf(s);

        // 方法引用的形式
        Function<String,Integer> f3 = Integer::valueOf;
    }
}

指定对象实例方法引用
package com.song.LambdaDemo;

import java.util.function.Function;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 16:53
 * @Description TODO
 */
public class ParticularInstanceRef {

    public Integer refMethod(String value) {
        return Integer.parseInt(value); // 将字符串转换成int
    }

    public static void main(String[] args) {
        ParticularInstanceRef pir=new ParticularInstanceRef();

        // 匿名内部类的写法
        Function<String,Integer> f1= new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return pir.refMethod(s);
            }
        };

        // Lambda 表达式的写法
        /*Function<String,Integer> f2= (s) ->
        {
            return pir.refMethod(s);
        };*/
        Function<String,Integer> f2= s -> pir.refMethod(s);

        // 方法引用
        Function<String,Integer> f3=pir::refMethod;
    }
}

特定类型任意对象方法引用

注意点:

  • 第一点:接口方法的参数比引用方法的参数多一个

  • 第二点:接口方法的第一个参数恰巧是调用引用方法的对象(其引用方法所在类或其父类的实例)

举例1

package com.song.LambdaDemo;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:06
 * @Description TODO
 */
public class Test {
    public  void a(){
        System.out.println(111);
    }

    public static void main(String[] args) {
        // 匿名内部类
        MyInter myInter=new MyInter() {
            @Override
            public void b(Test test) {
                test.a();
            }
        };

        // lambda 表达式
        MyInter myInter1= t -> t.a();

        // 方法引用
        MyInter myInter2= Test::a;

    }
}

@FunctionalInterface
interface MyInter{
    void b(Test test);
}

举例2

package com.song.LambdaDemo;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:17
 * @Description TODO
 */
public class Test02 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {

        MyInter1 myInter1= (t,param1,param2) -> t.a(param1,param2);

        MyInter1 myInter=Test02::a;
    }
}
@FunctionalInterface
interface MyInter1 {
    //该接口参数比上述的a方法参数数量多一个,除去第一个,其它类型一致(可兼容,如可以一个int,一个Integer)
    //且Test1::a的Test1是该入参类型Test1相同
    void d(Test02 d,int param1,int param2);
}

实例3

package com.song.LambdaDemo;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:12
 * @Description TODO
 */
public class Demo {
    public static void main(String[] args) {
        String[] stringArray = {"C", "a", "B"};

        // 第一种写法
        Comparator<String> comparator=new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        };
        Arrays.sort(stringArray,comparator);


        // 第一种写法 合起来
        Arrays.sort(stringArray, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });


        // Lambda 表达式写法
        Arrays.sort(stringArray,(o1,o2)->o1.compareTo(o2));

        // 方法引用写法
        Arrays.sort(stringArray, String::compareTo);

        Arrays.sort(stringArray,String::compareToIgnoreCase);// 忽略大小写的比较
        // [a, B, C]
        System.out.println(Arrays.toString(stringArray));

    }
}

超类方法引用
public class SupperRef {

    public static void main(String[] args) throws Exception {
        Sub sub = new Sub();
        // 10086
        System.out.println(sub.refMethod("10086"));
    }

    private static class Supper {
        private Integer supperRefMethod(String value) {
            return Integer.parseInt(value);
        }
    }

    private static class Sub extends Supper {
        private Integer refMethod(String value) {
            Function<String, Integer> function = super::supperRefMethod;
            // 等同于
            // Function<String,Integer> function1 = (String s) -> super.supperRefMethod(s);
            return function.apply(value);
        }
    }

}

构造器方法引用
package com.song.LambdaDemo;

import java.util.function.Function;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:34
 * @Description TODO
 */
public class ConstructorRef {
    public static void main(String[] args) {
        Student student=new Student("张三");

        // 匿名内部类的写法
        Function<String,Student> f1 = new Function<String, Student>() {
            @Override
            public Student apply(String s) {
                return new Student(s);
            }
        };
        
        // Lambda表达式的写法
        Function<String,Student> f2 = s -> new Student(s);
        
        // 方法引用写法
        Function<String,Student> f3= Student::new;
    }

}

class Student{
    private String name;



    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

数组构造器方法引用
package com.song.LambdaDemo;

import java.util.function.Function;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:38
 * @Description TODO
 */
public class ArrayCon {
    public static void main(String[] args) {
        Integer[] integers=new Integer[10];

        Function<Integer,Integer[]> f1=new Function<Integer, Integer[]>() {
            @Override
            public Integer[] apply(Integer integer) {
                return new Integer[integer];
            }
        };

        Function<Integer,Integer[]> f2= i -> new Integer[i];

        Function<Integer,Integer[]> f3 = Integer[]::new;
        
        f3.apply(10);
    }
}

Lambda表达式对集合的用法

为了能够让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对接。(这里只举一些常用的)

Collection接口

forEach( )方法演示:

package com.song.aggregate;

import java.util.ArrayList;
import java.util.function.Consumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:43
 * @Description TODO
 */
public class AggregateDemo01 {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        list.add("a");
        list.add("bc");
        list.add("def");
        list.add("hello");

        //写法1:(不用Lambda表达式)
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

        //写法2:(用Lambda表达式)
        list.forEach(s-> System.out.println(s));
        
        // 写法3:引用 静态方法引用
        list.forEach(System.out::println);

    }
}

list接口

sort()方法的演示

public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        list.add("hh");
        list.add("hi");
        list.add("def");
        list.add("abc");

        //写法1:(不用Lambda表达式)
        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1,String o2) {
                return o1.compareTo(o2);
            }
        });
	    //写法2:(用Lambda表达式)
        list.sort(((o1, o2) -> o1.compareTo(o2)));
           
        System.out.println("======分割线======");
        
        //效果和写法1一样
        list.forEach(s-> System.out.println(s));
	    list.forEach(System.out::println);
    }

Map接口

HashMap 的 forEach()

package com.song.aggregate;

import java.util.HashMap;
import java.util.function.BiConsumer;

/**
 * @author 小宋学java
 * @version 1.0
 * @Data 2022/12/9 17:50
 * @Description TODO
 */
public class AggregateDemo03 {
    public static void main(String[] args) {
        HashMap<String,Integer> hashMap=new HashMap<>();
        hashMap.put("k1",1);
        hashMap.put("k2",2);
        hashMap.put("k3",3);
        hashMap.put("k4",4);
        hashMap.put("k5",5);
        hashMap.put("k6",6);
        hashMap.put("k7",7);

        hashMap.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println("key:"+integer+"value:"+s);
            }
        });

        hashMap.forEach((k,v)-> System.out.println("key:"+k+"value:"+v));

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值