JAVA8特性 & Stream流 & 函数式编程Lambda表达式 & 双冒号(::)的用法和原理

一、自己的理解 函数式编程

从学习JAVA到现在一直都是面向对象的编程思想,一直以来的编程思想都是将相同类型的对象抽象出来形成类,但是函数式编程的思想和这种思想刚好相反,它是将方法抽象出来形成统一接口,输入的方式得到了本质的变化,是不是理解起来还是有点抽象,那么请看下图:

传统编程思想

方法不变,输入不同值得到不同结果。

image.png

函数式编程思想

值不变,输入不同方法得到不同结果。

image.png

二、Lambda表达式

Lambda表达式是Java 8引入的一种语法特性,它可以简化函数式编程的代码书写。

格式

@Test
public void test() throws Exception {
    Runnable runnable = () -> { System.out.println("thread success"); };
}
  • ():表示该Lambda表达式没有参数。在这个例子中,Lambda表达式不接受任何参数。
  • ->:箭头符号,将参数列表和Lambda表达式的主体分隔开。
  • {}:花括号内的代码块,表示Lambda表达式的具体逻辑。在这个例子中,Lambda表达式的主体是打印"thread success"。

条件

Lambda表达式只能用于函数式接口(Functional Interface)或者SAM(Single Abstract Method 单个抽象方法)类型。函数式接口是指只有一个抽象方法的接口,可以通过`@FunctionalInterface`注解进行标识。Runnable就是函数式接口。
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

应用

1、作为函数式接口的实例

Lambda表达式可以作为函数式接口的实例,函数式接口是只有一个抽象方法的接口。通过Lambda表达式,可以直接实现函数式接口的抽象方法,而不需要显式地编写实现类。

Runnable runnable = () -> {
    // 执行具体逻辑
};

2、作为方法的参数

Lambda表达式可以作为方法的参数进行传递。这样可以在调用方法时,直接在参数位置上使用Lambda表达式来定义方法的具体逻辑。

public void doSomething(Function<String, Integer> function) {
    // 执行具体逻辑
}

doSomething((String s) -> s.length());

3、作为方法的返回值

Lambda表达式可以作为方法的返回值进行返回。这样可以在方法内部使用Lambda表达式来定义方法的具体逻辑,并将其返回给调用者。

public Function<String, Integer> createFunction() {
    return (String s) -> s.length();
}

三、Lambda表达书中的双冒号

语法

list.forEach(System.out::println);

应用

静态方法引用

可以引用一个类的静态方法。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(System.out::println);

实例方法引用

可以引用一个特定对象的实例方法。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(String::toUpperCase);

构造函数引用

可以引用一个类的构造函数。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Person> persons = numbers.stream().map(Person::new).collect(Collectors.toList());

四、Stream流的用法

1 filter(Predicate<T> predicate)

根据给定的条件过滤出符合条件的元素并返回一个新的Stream。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
                                   .filter(num -> num % 2 == 0)
                                   .collect(Collectors.toList());
// 过滤出偶数 [2, 4]
  • Predicate<T>函数式接口,可以理解为是一个返回值为Boolean类型的方法,T为输入类型。

2 map(Function<T, R> mapper)

将每个元素通过给定的映射函数转换为另一种类型,并返回一个新的Stream。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
                                 .map(String::length)
                                 .collect(Collectors.toList());
// 转换为名字的长度 [5, 3, 7]
  • Function<T, R>函数式接口,可以理解为是一个转化方法,T为输入,R为输出。

3 flatMap(Function<T, Stream<R>> mapper)

将每个元素通过给定的映射函数转换为Stream并将多个Stream合并为一个Stream。

List<List<Integer>> numbers = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6));
List<Integer> flattenedNumbers = numbers.stream()
                                        .flatMap(List::stream)
                                        .collect(Collectors.toList());
// 合并成一个列表 [1, 2, 3, 4, 5, 6]
  • Function<T, Stream<R>>函数式接口,可以理解为是一个转化Stream方法,T为输入,Stream<R>为输出。

4 distinct()

去除重复元素,返回一个去重后的新Stream。

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);
List<Integer> distinctNumbers = numbers.stream()
                                       .distinct()
                                       .collect(Collectors.toList());
// 去除重复的数字 [1, 2, 3, 4, 5]

5 sorted()

对Stream中的元素进行排序,默认按照自然顺序进行排序。

List<Integer> numbers = Arrays.asList(5, 2, 4, 1, 3);
List<Integer> sortedNumbers = numbers.stream()
                                     .sorted()
                                     .collect(Collectors.toList());
// 排序后的数字列表 [1, 2, 3, 4, 5]

6 sorted(Comparator<T> comparator)

根据给定的Comparator对Stream中的元素进行排序。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream()
                               .sorted(Comparator.reverseOrder())
                               .collect(Collectors.toList());
// 按字母降序排序 ["Charlie", "Bob", "Alice"]

7 limit(long maxSize)

截取Stream中的前maxSize个元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limitedNumbers = numbers.stream()
                                      .limit(3)
                                      .collect(Collectors.toList());
// 截取前3个数字 [1, 2, 3]

8 skip(long n)

跳过Stream中的前n个元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skippedNumbers = numbers.stream()
                                      .skip(2)
                                      .collect(Collectors.toList());
// 跳过前2个数字 [3, 4, 5]

9 forEach(Consumer<T> action)

对Stream中的每个元素执行给定的操作。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
     .forEach(System.out::println);
// 打印每个名字

10 collect(Collector<T, A, R> collector)

将Stream中的元素收集到一个集合或数据结构中,并返回结果。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> collectedNumbers = numbers.stream()
                                        .collect(Collectors.toList());
// 收集到列表中 [1, 2, 3, 4, 5]

扩展(可以不看):


Collector<T, A, R> 是 Java 中用于将流中的元素进行收集的接口。它定义了三个泛型参数:

T:表示流中元素的类型。

A:表示用于累积部分结果的对象的类型,也可以看作是中间结果的类型。

R:表示收集操作的最终结果的类型。


Collector<T, A, R> 接口中定义了以下五个方法:

Supplier<A> supplier():用于创建一个初始的结果容器对象。

BiConsumer<A, T> accumulator():用于将流中的元素累积到结果容器中。

BinaryOperator<A> combiner():用于将两个结果容器合并为一个。

Function<A, R> finisher():用于将结果容器转换为最终结果。

Set<Characteristics> characteristics():用于获取收集器的特性,返回一个包含特性的不可变 Set 集合。

重点:


Collector<T, A, R> collector JAVA8中有专门定义收集器的工具类Collectors,以下列出常用的方法:

toList()

将流中的元素收集到一个 List 中。

List<String> names = Stream.of("John", "Alice", "Bob")
                        .collect(Collectors.toList());

toSet()

将流中的元素收集到一个 Set 中。

Set<Integer> numbers = Stream.of(1, 2, 3, 4, 5)
                        .collect(Collectors.toSet());

toMap()

将流中的元素根据指定的键和值的提取函数收集到一个 Map 中。

Map<String, Integer> ageMap = Stream.of("John", "Alice", "Bob")
                                .collect(Collectors.toMap(Function.identity(), String::length));

counting()

对流中的元素进行计数。

long count = Stream.of("John", "Alice", "Bob")
            .collect(Collectors.counting());

summingInt()

对流中的元素进行求和,返回一个整数。

int sum = Stream.of(1, 2, 3, 4, 5)
            .collect(Collectors.summingInt(Integer::intValue));

averagingInt()

对流中的元素进行求平均值,返回一个 double 类型。

double average = Stream.of(1, 2, 3, 4, 5)
                .collect(Collectors.averagingInt(Integer::intValue));

joining()

将流中的元素拼接成一个字符串。

String result = Stream.of("Hello", "World")
                .collect(Collectors.joining(", "));

maxBy()

根据指定的比较器选择流中的最大元素。

Optional<String> maxName = Stream.of("John", "Alice", "Bob")
                        .collect(Collectors.maxBy(Comparator.naturalOrder()));

minBy()

根据指定的比较器选择流中的最小元素。

Optional<String> minName = Stream.of("John", "Alice", "Bob")
                        .collect(Collectors.minBy(Comparator.naturalOrder()));

groupingBy()

根据指定的分类函数对流中的元素进行分组。

Map<Character, List<String>> groupedNames = Stream.of("John", "Alice", "Bob")
                                            .collect(Collectors.groupingBy(s -> s.charAt(0)));

partitioningBy()

根据指定的条件对流中的元素进行分区。

Map<Boolean, List<String>> partitionedNames = Stream.of("John", "Alice", "Bob")
                                                .collect(Collectors.partitioningBy(s -> s.length() > 3));

mapping()

对流中的元素进行映射,并将结果收集到一个集合中。

List<Integer> lengths = Stream.of("John", "Alice", "Bob")
                        .collect(Collectors.mapping(String::length, Collectors.toList()));

filtering()

根据指定的条件过滤流中的元素,并将结果收集到一个集合中。

List<String> filteredNames = Stream.of("John", "Alice", "Bob")
                            .collect(Collectors.filtering(s -> s.length() > 3, Collectors.toList()));

reducing()

根据指定的规约操作对流中的元素进行规约。

Optional<Integer> sum = Stream.of(1, 2, 3, 4, 5)
                        .collect(Collectors.reducing(Integer::sum));

collectingAndThen()

对流中的元素进行收集,并执行一个最终的转换操作。

String longestName = Stream.of("John", "Alice", "Bob")
                        .collect(Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(String::length)), Optional::get));

toCollection()

将流中的元素收集到指定的集合类型中。

LinkedList<String> names = Stream.of("John", "Alice", "Bob")
                            .collect(Collectors.toCollection(LinkedList::new));

summarizingInt()

对流中的元素进行统计,返回一个统计结果对象。

IntSummaryStatistics statistics = Stream.of(1, 2, 3, 4, 5)
                                    .collect(Collectors.summarizingInt(Integer::intValue));

groupingByConcurrent()

并发地根据指定的分类函数对流中的元素进行分组。

ConcurrentMap<Character, List<String>> concurrentGroupedNames = Stream.of("John", "Alice", "Bob")
                                                                .collect(Collectors.groupingByConcurrent(s -> s.charAt(0)));

summingDouble()

对流中的元素进行求和,返回一个 double 类型。

double sum = Stream.of(1.0, 2.0, 3.0, 4.0, 5.0)
            .collect(Collectors.summingDouble(Double::doubleValue));

toConcurrentMap()

将流中的元素根据指定的键和值的提取函数收集到一个并发的 Map 中。

ConcurrentMap<String, Integer> concurrentAgeMap = Stream.of("John", "Alice", "Bob")
                                                .collect(Collectors.toConcurrentMap(Function.identity(), String::length));

11 toArray()

将Stream中的元素转换为数组。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Integer[] numberArray = numbers.stream()
                               .toArray(Integer[]::new);
// 转换为数组 [1, 2, 3, 4, 5]

12 anyMatch(Predicate<T> predicate)

判断Stream中是否存在满足给定条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean hasEvenNumber = numbers.stream()
                              .anyMatch(num -> num % 2 == 0);
// 是否有偶数,结果为true

13 allMatch(Predicate<T> predicate)

判断Stream中的所有元素是否都满足给定条件。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEvenNumbers = numbers.stream()
                               .allMatch(num -> num % 2 == 0);
// 是否都是偶数,结果为false

14 noneMatch(Predicate<T> predicate)

判断Stream中是否不存在满足给定条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noEvenNumber = numbers.stream()
                             .noneMatch(num -> num % 2 == 0);
// 是否没有偶数,结果为false

15 findFirst()

返回Stream中的第一个元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstNumber = numbers.stream()
                                       .findFirst();
// 第一个数字,结果为Optional[1]

16 findAny()

返回Stream中的任意一个元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> anyNumber = numbers.stream().findAny();
// 任意一个数字,结果为Optional[1]或其他数字

17 count()

返回Stream中的元素个数。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream().count();
// 元素个数,结果为5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值