Java 8 新特性——Lambda表达式

一.Lambda表达式简介

Lambda 表达式是 Java 8 的一个新特性,Lambda 表达式可以代替一部分的匿名内部类,可以使代码变的更加简洁紧凑。

Lambda 表达式只能实现函数式接口,什么是函数式接口呢?就是一个接口有且只有一个抽象方法。函数式接口可以添加 @FunctionalInterface 注解,非函数式接口添加 @FunctionalInterface 注解后,编译会报错。

二.Lambda表达式语法

(parameters) -> expression

(parameters) -> { statements; }

  • paramaters:类似于方法的形参列表,这里指的是函数式接口中抽象方法的参数。参数的类型即可以声明也可以省略,如果只有一个参数,括号也可以省略
  • ->:类似于 JavaScript 中的箭头函数 
  • 方法体:函数式接口中抽象方法的实现。如果方法体只有一个语句,大括号是可以省略

三.Lambda表达式基本使用

1.无参数无返回值

public class Demo15 {

    interface NoParameterNoReturn {
        // 无参数无返回值
        void test();
    }

    public static void main(String[] args) {
        NoParameterNoReturn noParameterNoReturn = () -> {
            System.out.println("无参数无返回值");
        };
        noParameterNoReturn.test();
    }

}

执行结果:

无参数无返回值

Process finished with exit code 0

 2.有参数无返回值

public class Demo16 {

    interface OneParameterNoReturn {
        // 一个参数无返回值
        void test(String str);
    }

    interface TwoParameterNoReturn {
        // 两个参数无返回值
        void test(String str1, String str2);
    }

    public static void main(String[] args) {
        // 一个参数时,括号阔以省略
        OneParameterNoReturn oneParameterNoReturn = str -> {
            System.out.println(str);
        };
        oneParameterNoReturn.test("一个参数无返回值");

        TwoParameterNoReturn twoParameterNoReturn = (str1, str2) -> {
            System.out.println(str1 + str2);
        };
        twoParameterNoReturn.test("两个参数", "无返回值");
    }

}

执行结果:

一个参数无返回值
两个参数无返回值

Process finished with exit code 0

 3.无参数有返回值

public class Demo17 {

    interface NoParameterHasReturn {
        // 无参数有返回值
        String test();
    }

    public static void main(String[] args) {
        // 如果方法体只有一个表达式,大括号可以省略
        // 如果主体只有一个表达式返回值则编译器会自动返回值,return 关键字可以省略
        NoParameterHasReturn noParameterHasReturn = () -> "无参数有返回值";
        System.out.println(noParameterHasReturn.test());
    }

}

执行结果:

无参数有返回值

Process finished with exit code 0

4.有参数有返回值

public class Demo18 {

    interface OneParameterHasReturn {
        // 一个参数有返回值
        String test(String str);
    }

    interface TwoParameterHasReturn {
        // 两个参数有返回值
        String test(String str1, String str2);
    }

    public static void main(String[] args) {
        // 如果方法体只有一个表达式,大括号可以省略
        // 如果主体只有一个表达式返回值则编译器会自动返回值,return 关键字可以省略
        OneParameterHasReturn oneParameterHasReturn = (str) -> str;
        System.out.println(oneParameterHasReturn.test("一个参数有返回值"));

        TwoParameterHasReturn twoParameterHasReturn = (str1, str2) -> {
            String result = str1 + str2;
            return result;
        };
        System.out.println(twoParameterHasReturn.test("两个参数", "有返回值"));
    }

}

执行结果:

一个参数有返回值
两个参数有返回值

Process finished with exit code 0

四.Lambda表达式变量作用域

  • Lambda 表达式相当于一个匿名内部类,匿名内部类只能使用被 final 修饰的局部变量。Lambda 表达式中使用的局部变量可以不用声明为 final,但是必须不可被后面的代码修改,即隐性的具有 final 的语义。
public class Demo19 {

    interface TestScope {
        void test();
    }

    public static void main(String[] args) {
        // 定义一个局部变量
        int age = 18;
        TestScope testScope = () -> {
            // 可以使用局部变量,但是不能修改其值
            System.out.println("局部变量 age = " + age);
        };
        testScope.test();
    }
}
  •  在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者变量。

五.集合中Lambda表达式的应用

在 Java 1.8 中给集合新增了很多方法,方法的参数类型是函数式接口,所以在使用这些方法时,可以大量使用 Lambda 表达式,让我们的代码更简洁紧凑。

接口新增方法
Iterable
default void forEach(Consumer<? super T> action)
Collection
default boolean removeIf(Predicate<? super E> filter)
List
default void sort(Comparator<? super E> c) 
default void replaceAll(UnaryOperator<E> operator) 
Map
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp)
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp)
default void forEach(BiConsumer<? super K, ? super V> action)
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 
default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) 
default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction)
default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction)
default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction)

1.List的forEach使用

通过查看源码,forEach 方法接收一个 Consumer 类型的参数,Consumer 是一个函数式接口,里面只有一个 accept 的抽象方法,所以我们可以通过 Lamdba 表达式实现 Consumer 接口。

代码示例:

public class Demo20 {
    public static void main(String[] args) {
        ArrayList<String> strings = new ArrayList<>();
        strings.add("1");
        strings.add("2");
        strings.add("3");

        // 使用 forEach 遍历 List 集合
        strings.forEach(str -> System.out.println(str));

    }
}

执行结果:

1
2
3

Process finished with exit code 0

2.Map的merge使用

通过查看源码,merge 方法接收三个参数,一个 key,一个 value,一个 BiFunction 类型的参数,BiFunction 是一个函数式接口,里面只有一个 apply 的抽象方法,所以我们可以通过 Lamdba 表达式实现 BiFunction 接口。

default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        // 从 map 中获取 key 的值
        V oldValue = get(key);
        // 如果 key 在 map 中不存在,则直接把传进来的 value 赋值给 newValue
        // 如果 key 在 map 中存在,则调用 BiFunction 的 apply 方法计算出 newValue 的值
        // 传个BiFunction 的 apply 方法的参数,一个是从 map 中取出的值,一个是传入的 value
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if (newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }

代码示例:

没有使用 merge 方法实现的代码

public class Demo21 {
    public static void main(String[] args) {
        // 统计该字符串中各个字符出现的次数
        String str = "abcdehaakdhfnzczxhhiaepfasdczkba";
        HashMap<Character, Integer> hashMap = new HashMap<>();
        for (char c : str.toCharArray()) {
            Integer integer = hashMap.get(c);
            if (integer != null) {
                hashMap.put(c, integer + 1);
            } else {
                hashMap.put(c, 1);
            }
        }
        hashMap.forEach((key, value) -> {
            System.out.println(key + "出现了" + value + "次");
        });
    }
}

使用 merge 方法实现的代码

public class Demo21 {
    public static void main(String[] args) {
        // 统计该字符串中各个字符出现的次数
        String str = "abcdehaakdhfnzczxhhiaepfasdczkba";
        HashMap<Character, Integer> hashMap = new HashMap<>();
        for (char c : str.toCharArray()) {
//            hashMap.merge(c, 1, (a, b) -> {
//                return a + b;
//            });
            // Integer::sum 等价于上面的写法
            hashMap.merge(c, 1, Integer::sum);
        }
        hashMap.forEach((key, value) -> {
            System.out.println(key + "出现了" + value + "次");
        });
    }
}

 两种方式的执行结果是一致的

a出现了6次
b出现了1次
c出现了1次

Process finished with exit code 0

上述列表中还有很多方法,这里就不一一举例说明了!!!大家如果感兴趣,可以自己动手敲一敲,同时,欢迎大家在评论区留言,一起讨论 Lambda 表达式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值