Java8新特性之Lambda,Stream,Optional

本文深入介绍了Java8的三大重要特性:Lambda表达式、Stream API和Optional类。Lambda表达式让代码更简洁,通过函数式接口传递行为。Stream API提供了高效的数据处理方式,如过滤、映射、规约等操作。Optional类用于避免空指针异常,提供多种安全访问值的方法。文章详细讲解了这些特性的用法和最佳实践。

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

开发自己的收集器以获得更好的性能

前言

本文是学习java8新特性过程产生的一些笔记,参考的资料有:Java8实战,Java 8的新特性—终极版

1. Lambda表达式

1.1 何为Lamdba表达式

Lambda表达式理解为简洁地表示可传递的一种表达式:它没有名称,但有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成,例如:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

Lambda表达式有返回值,返回值的类型也由编译器推理得出。如果Lambda表达式中的语句块只有一行,则可以不用使用return语句,例如:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
1.2 在哪里使用Lambda表达式

Lambda的设计者们为了让现有的功能与Lambda表达式良好兼容,考虑了很多方法,于是产生了函数接口这个概念。函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式。java.lang.Runnable和java.util.concurrent.Callable是函数式接口的最佳例子。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),举个简单的函数式接口的定义:

@FunctionalInterface

public interface Functional {
   
    void method();
}

不过有一点需要注意,默认方法和静态方法不会破坏函数式接口的定义,因此如下的代码是合法的。

@FunctionalInterface

public interface FunctionalDefaultMethods {
   
    void method();
        
    default void defaultMethod() {
               
    }        
}
1.3 正确使用Lambda表达式
1.3.1 使用函数式接口传递行为
@FunctionalInterface
public interface Test<T> {
   
    boolean test(T t);
}
1.3.2 执行一个行为
public static <T> List<T> filterApples(List<T> input, Test<T> p) {
      
    List<T> result = new ArrayList<>();   
    for (T e : input) {
           
        if (p.test(e)) {
              
             result.add(e);       
        }    
    }
    return result;
}

1.3.3 传递一个Lamdba表达式
List<Apple> result = filterApples(input, (Apple apple) -> apple.getColor().equals("green"));

1.4 函数式接口

表达式之前已经使用过自定义的函数式接口了,它只定义了一个抽象方法。Java API 中已经有了几个函数式接口了,这几个我们可以直接使用,比如Comparable,Runnalble和Callable等都是我们熟悉的接口。在java8的java.util.function包中引入了几个新的函数式接口,如Predicate,Consumer,Function等是比较常用的接口。

1.4.1 Predicate

Predicate接口中定义了一个抽象方法test(),它接受泛型对象,并返回boolean。我们需要一个涉及泛型T的布尔表达式的时候就可以使用这个接口,如:

public static <T> List<T> filterApples(List<T> input, 
Predicate<T> p) {
      
    List<T> result = new ArrayList<>();
        for (T e : input) {
   
            if (p.test(e)) {
   
                result.add(e);
             } 
         }   
    return result;
}

List<Apple> result = filterApples(input, (Apple apple) ->apple.getColor().equals("green")  &&apple.getWeight() > 2 && apple.getWeight() < 45);

1.4.2 Consumer

Comsumer接口中定义了一个名叫accpet()的抽象方法,接受泛型对象并且返回void,正如接口名字那样,我们可以用它来消费类型为T 的对象,但返回void。比如遍历集合中的元素并打印它。

public static<T> void forEach(List<T> list, Consumer<T> 
consumer) {
       
    for (T t : list) {
      
        consumer.accept(t); 
     }
 }
 
 List<Integer> list = Arrays.asList(1,2,5,8,6);
 forEach(list, (i) -> System.out.print(i + "\t"));

1.4.3 Function

Function<T,R>接口中定义了一个名叫apply()的抽象方法,接受泛型T的对象并且返回泛型R的对象,如果你需要定义一个Lambda,将输入对象的信息映射到输出,就可以使用这个接口。

public static <T, R> List<R> map(List<T> list, 
Function<T, R> f) {
   
    List<R> res = new ArrayList<>();
    for (T t : list) {
   
        res.add(f.apply(t)); 
    }  
    return res;
 }
List<String> str = Arrays.asList("red", "green", "blue");
forEach(map(str, (s) -> s.length()), (i) -> System.out.print(i + "\t"));

1.4.4 自定义函数式接口

可以使用@FunctionalImterface注解自定义函数式接口

@FunctionalInterface
public interface Test<T> {
   
    boolean test(T t);
}
1.5 方法引用
1.5.1 什么是方法引用

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。

1.5.2方法引用的形式

方法引用的标准形式是:类名::方法名。(注意:只需要写方法名,不需要写括号)有以下四种形式的方法引用:

类型 示例
引用静态方法 ContainingClass::staticMethodName
引用某个对象的实例方法 containingObject::instanceMethodName
引用某个类型的任意对象的实例方法 ContainingType::methodName
引用构造方法 ClassName::new

2. 函数式数据处理

2.1 Streams流

流是“从支持数据处理操作的原生成的一系列元素“;
流利用内部迭代:迭代通过filter,map,sorted等操作被抽橡掉了。

新增的Stream API(java.util.stream)将生成环境的函数式编程引入了Java库中。这是目前为止最大的一次对Java库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。

Stream API极大得简化了集合操作(后面我们会看到不止是集合),首先看下这个叫Task的类:

public class Streams  {
   
    private enum Status {
   
        OPEN, CLOSED
    };
    
    private static final class Task {
   
        private final Status status;
        private final Integer points;

        Task( final Status status, final Integer points ) {
   
            this.status = status;
            this.points = points;
        }
        
        public Integer getPoints() {
   
            return points
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值