JDK8新特性:lambda使用和例子

本文深入探讨了Java中Lambda表达式的应用,展示了如何使用Lambda简化线程创建、接口实现、集合排序、遍历及流处理等操作,同时介绍了Predicate、Map、Reduce、Collect等高级功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)

经典例子:

@Test
public void demo () {
    Runnable runnable = new Runnable(){
        public void run(){
            System.out.println("Test thread");
        }
    };
    new Thread(runnable).start();
}
/*
Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心;
为了指定run的方法体,不得不需要Runnable接口的实现类;
为了省去定义一个RunnableImpl实现类的麻烦,不得不使用匿名内部类;
必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;
而实际上,似乎只有方法体才是关键所在
*/

转换为Lambda的写法是:

@Test
public void lambdaDemo () {
    new Thread(() -> System.out.println("Test lambda")).start();
}
/*
上例中,核心代码其实只是如下所示的内容:() -> System.out.println(“Test lambda")
*/
Lambda格式:

(参数类型 参数名称) -> { 代码语句 }
格式说明:

  • 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
  • ->是新引入的语法格式,代表指向动作。
  • 大括号内的语法与传统方法体要求基本一致
实用案例:
public interface Cooker { 
    void makeFood(); 
}
public class demo01 {
    public static void main(String[] args) {
        invokeCook(() -> {
            System.out.println("吃饭啦!");
        });
    }

    private static void invokeCook(Cooker c){
        c.makeFood();
    }
}
排序:
// 老式的写法
public class Demo02 {
    public static void main(String[] args) {
          // 本来年龄乱序的对象数组
        Person[] array = {
            new Person("chock", 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("chock", 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);
        }
    }
}
遍历:
@Test
public void eachLambda () {
    List<String> strList = Arrays.asList("chock", "聪", "儿");
    strList.forEach(str -> System.out.println(str));
}

// 使用lambda的遍历,使用foreach方法,其中代码中的str表示遍历中的每个元素,代码块部分可以对该元素进行不同的操作
Predicate的使用:

jdk8中提供了Predicate的条件表达式方法,可以简便地进行多条件操作
其中Predicate之间提供了and(),or() 和 negate()方法来对多条件之间进行 与 或 取反 操作

@Test
public void predicateLambda () {
    List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
    Predicate<String> unStartJ = a -> !a.startsWith("J");
    Predicate<String> longerFourLetter = a -> a.length() > 4;
    languages.stream().filter(unStartJ.and(longerFourLetter)).forEach(str -> System.out.println(str));
}
Map 和 Reduce操作:

其中Map操作是可以对流中的数据进行再处理

@Test
public void mapLambda () {
    List<Integer> beforeVals = Arrays.asList(100, 200, 300, 400, 500);
    beforeVals.stream().map(n -> n / 100) .forEach(System.out::println);
}

// 输出的结果为: 12345

Reduce操作是在流中得到特定的值,这个特定的值是经过指定的计算后得出,以下例子中是计算所有购买商品打8折后的总价
首先使用map算出所有单件商品的8折价格是多少,然后使用reduce方法进行求和

这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。

@Test
public void reduceLambda() {
    double bill = Stream.of(100, 200, 300, 400, 500).map((cost) -> .8 * cost)
            .reduce((sum, cost) -> sum + cost)
            .get();

    System.out.println(bill); // 1200.0
}

变形:网上购买后需要添加10块钱的邮费,所以reduce的参数中多了一个identity的初始值(10)
第二个变形,与第一种变形相同的是都会接受一个BinaryOperator函数接口,不同的是其会接受一个identity参数,用来指定Stream循环的初始值。如果Stream为空,就直接返回该值。

@Test
public void reduceLambda() {
    double bill = Stream.of(100, 200, 300, 400, 500).map((cost) -> .8 * cost)
            .reduce(10.0, (sum, cost) -> {
                sum += cost;
                return sum;
            });

    System.out.println(bill); // 1210.0
}
Collect操作:

collect可以对流处理后的结果进行归总

@Test
public void lastOperationLambda () {
    List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany",
            "Italy", "U.K.","Canada");
    String G7Countries = G7.stream().map(x -> x.toUpperCase())
            .collect(Collectors.joining(", "));
    System.out.println(G7Countries);                                     // Collectors.join() 把List<String> 转换为拼接字符串

    G7.stream().map(x -> x.toUpperCase())
            .collect(Collectors.toList()).forEach(System.out::println); // Collectors.toList() 把处理结果重新封装为list
}
IntSummaryStatistics:

主要配合Stream进行使用,可以对数字结果进行常规的函数操作,包括最大最小值,平均值等……

@Test
public void intSummaryStatisticsLambda () {
    List<Integer> vals = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
    IntSummaryStatistics summary = vals.stream().mapToInt(n -> n + 2).summaryStatistics();
    System.out.println("最大值:" + summary.getMax() + " 平均值:" + summary.getAverage());
}
distinct和skip:

distinct主要是对列表中的数据进行去重,skip是在后续操作中跳过多少个元素

@Test
public void distinctAndSkipLambda() {
    List languages = Arrays.asList("Java", "Scala", "C++", "Java", "Haskell", "Lisp");
    languages.stream().distinct().skip(2).forEach(n -> System.out.println(n));
}
list TO map 和 分组:
@Test
public void listToMapAndGroupByLambda () {
    List<Person> list = new ArrayList<Person>() {{
        add(new Person(1, "name1"));
        add(new Person(2, "name2"));
        add(new Person(3, "name3"));
    }};

    // list转换为id为key,对象为val的MAP
    Map<Integer, Person> map = list.stream().collect(Collectors.toMap(Person::getId, n -> n));
    // list按照id进行分组,在id存在重复的情况下可以拆分
    Map<Integer, List<Person>> map2 = list.stream().collect(Collectors.groupingBy(Person::getId));
}
Collectors 类的静态工厂方法汇总:
方法名返回类型说明
toListList把流中所有项目收集到一个 List
toSetSet把流中所有项目收集到一个 Set,删除重复项
toCollectionCollection把流中所有项目收集到给定的供应源创建的集合menuStream.collect(toCollection(), ArrayList::new)
countingLong计算流中元素的个数
sumIntInteger对流中项目的一个整数属性求和
averagingIntDouble计算流中项目 Integer 属性的平均值
summarizingIntIntSummaryStatistics收集关于流中项目 Integer 属性的统计值,例如最大、最小、 总和与平均值
joiningString连接对流中每个项目调用 toString 方法所生成的字符串collect(joining(", "))
maxByOptional一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()
minByOptional一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()
reducing归约操作产生的类型从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果应用转换函数int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))
groupingByMap<K, List>根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键
partitioningByMap<Boolean,List>根据对流中每个项目应用谓词的结果来对项目进行分区
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值