JDK1.8新特性--Lambda表达式

 非原创,知识总结性文章

1、Lambda表达式的介绍

函数式编程思想概述

在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。

传统写法代码示例

public class demo01 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable(){
            public void run(){
                System.out.println("多线程任务执行");
            }
        };
        new Thread(runnable).start();
    }
}

说明:

  • Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心;
  • 为了指定run的方法体,不得不需要Runnable接口的实现类;
  • 为了省去定义一个RunnableImpl实现类的麻烦,不得不使用匿名内部类;
  • 必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;
  • 而实际上,似乎只有方法体才是关键所在

上述示例使用Lambda的写法

public class demo01 {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println("多线程启动");
        }).start();
    }
}

上例中,核心代码其实只是如下所示的内容:() -> System.out.println("多线程任务执行!")

Lambda标准格式

Lambda省去面向对象的条条框框,格式由3个部分组成:
  • 一些参数;
  • 一个箭头;
  • 一段代码。
    Lambda表达式的标准格式为:(参数类型 参数名称) -> { 代码语句 }
    格式说明:
  • 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔;
  • ->是新引入的语法格式,代表指向动作;
  • 大括号内的语法与传统方法体要求基本一致。

练习:使用Lambda标准格式(无参无返回)

给定一个厨子Cooker接口,内含唯一的抽象方法makeFood,且无参数、无返回值。如下:
public interface Cooker {
    void makeFood();
}

在下面的代码中,请使用Lambda的标准格式调用invokeCook方法,打印输出“吃饭啦!”字样:

public class demo01 {
    public static void main(String[] args) {
        invokeCook(() -> {
            System.out.println("吃饭啦!");
        });

    }
    private static void invokeCook(Cooker c){
        c.makeFood();
    }
}

Lambda的参数和返回值

需求:使用Lambda表达式对存在数组中的Person类型的对象数据按照年龄的降序输出。

传统写法:

public class Demo02 {
    public static void main(String[] args) {
        // 本来年龄乱序的对象数组
        Person[] array = {
            new Person("古力娜扎", 19),
            new Person("迪丽热巴", 18),
            new Person("马尔扎哈", 20) };

        // 匿名内部类
        Comparator<Person> comp = new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o2.getAge() - o1.getAge();
            }
        };
        Arrays.sort(array, comp); // 第二个参数为排序规则,即Comparator接口实例

        for (Person person : array) {
            System.out.println(person);
        }
    }
}

Lambda写法:

public class demo02 {
    public static void main(String[] args) {
        // 本来年龄乱序的对象数组
        Person[] array = {
                new Person("古力娜扎", 19),
                new Person("迪丽热巴", 18),
                new Person("马尔扎哈", 20) };

        Arrays.sort(array,(Person p1,Person p2) -> {
            return p2.getAge() - p1.getAge();
        });

        for (Person person : array) {
            System.out.println(person);
        }
    }
}

Lambda省略格式

  Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。例如上例还可以使用Lambda的省略写法:
public static void main(String[] args) {
    invokeCalc(120, 130, (a, b) -> a + b);
}

省略规则:
在Lambda标准格式的基础上,使用省略写法的规则为:

  • 小括号内参数的类型可以省略;
  • 如果小括号内有且仅有一个参数,则小括号可以省略;
  • 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
    注意:关于第三点如果省略一个,那么必须同时都得省略。

2、Lambda表达式的应用

Lambda表达式的使用条件是
  • 使用lambda表达式的类型必须是一个只含有一个抽象方法的借口
  • lambda只能使用final修饰的变量

forEach遍历Map

//1.forEach遍历Map
System.out.println("\n1.forEach遍历Map");
Map<String, Object> map = new HashMap<>();
map.put("key1", 11);
map.put("key2", 12);
map.put("key3", 13);
map.put("key4", 14);
map.forEach((key,value)->{
    System.out.println("key:"+key+",value:"+value);
});

输出:
1.forEach遍历Map
key:key1,value:11
key:key2,value:12
key:key3,value:13
key:key4,value:14

forEach遍历List

//2.forEach遍历List
System.out.println("\n2.forEach遍历List");
List<Integer> list =  new ArrayList<Integer>() ;
list.add(1);
list.add(2);
list.add(3);
list.forEach(value->System.out.println(value));

输出:
2.forEach遍历List
1
2
3

在多线程中使用Lambda表达式

//3.在多线程中使用Lambda表达式
System.out.println("\n3.在多线程中使用Lambda表达式");
new Thread(()->System.out.println("new Thread start")).start();

输出:
3.在多线程中使用Lambda表达式
new Thread start

自定义Lambda表达式功能

//4.自定义Lambda表达式功能
interface MathOperator{
    int operator(int a, int b);
    
}
public static void calc(int a ,int b, MathOperator operator){
    System.out.println(operator.operator(a, b));
}

System.out.println("\n4.自定义Lambda表达式功能");
MathOperator add = (a,b)->a+b ;
MathOperator sub = (a,b)->a-b ;
MathOperator mul = (a,b)->a*b ;
MathOperator div = (a,b)->a/b ;

calc(3, 5, add);
calc(3, 5, sub);
calc(3, 5, mul);
calc(3, 5, div);

输出:
4.自定义Lambda表达式功能
8
-2
15
0

Predicate接口实现数据过滤

System.out.println("\n5.Predicate接口实现数据过滤");
List<String> filterList = new LinkedList<>() ;
filterList.add("1");
filterList.add("abc");
filterList.add("java");
filterList.add("python2");
filterList.add("python3");
filterList.add("c++");
filture(filterList, str->str.startsWith("j")) ;
//单条件过滤
filterList.stream().filter(str->str.contains("++")).forEach(value->System.out.println(value)) ;
//多条件逻辑过滤
Predicate<String> startWith = str->str.startsWith("p") ;
filterList.stream().filter(startWith.and(str->str.contains("2"))).forEach(value->System.out.println(value)) ;

输出:
5.Predicate接口实现数据过滤
java
c++
python2

Lambda的map和reduce操作

/3.在多线程中使用Lambda表达式
System.out.println("\n6.Lambda的map和reduce操作");
List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
//map操作让每一个元素加上它之前的0.12倍
costBeforeTax.stream().map(cost -> cost+0.12*cost).forEach(System.out::println);
System.out.println(costBeforeTax.stream().reduce((sum,cost)->sum+cost).get()); //求和

输出:
6.Lambda的map和reduce操作
112.0
224.0
336.0
448.0
560.0
1500

创建一个字符串列表,每个字符串长度大于2

System.out.println("\n7.创建一个字符串列表,每个字符串长度大于2");
List<String> strList = Arrays.asList(new String[]{"abc","de","abcde"});
List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

输出:
7.创建一个字符串列表,每个字符串长度大于2
Original List : [abc, de, abcde], filtered list : [abc, abcde]

获取数字的个数、最小值、最大值、总和以及平均值

System.out.println("\n8.获取数字的个数、最小值、最大值、总和以及平均值");
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());

输出:
8.获取数字的个数、最小值、最大值、总和以及平均值
Highest prime number in List : 29
Lowest prime number in List : 2
Sum of all prime numbers : 129
Average of all prime numbers : 12.9

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容