【Java 开发学习】自定义 LINQ 语法实现数据集合操作

219 阅读6分钟

🙏废话不多说系列,直接开整🙏

一、LinQ 简介

LINQ(Language Integrated Query)是C#等编程语言中用于查询和操作数据的一种技术。在LINQ中,有许多操作符用于构建查询和转换数据。以下是一些常用的LINQ操作符:

  1. Where:用于根据指定的条件筛选序列的元素。
  2. Select:用于根据输入序列中的元素创建相应的输出序列中的元素。输出序列中的元素类型可以与输入序列中的元素类型相同,也可以不同。
  3. SelectMany:用于根据输入序列中的每一个元素,在输出序列中创建相应的零个或者多个元素。与Select操作符不同,SelectMany操作符可以创建多个输出元素。
  4. OrderBy:按升序对序列的元素进行排序。
  5. OrderByDescending:按降序对序列的元素进行排序。
  6. ThenBy:对已排序的序列按升序进行进一步排序。
  7. ThenByDescending:对已排序的序列按降序进行进一步排序。
  8. GroupBy:根据指定的键对序列的元素进行分组。
  9. Join:将两个序列的元素进行关联。
  10. Union:返回两个序列的并集。
  11. Distinct:返回序列的不重复元素。
  12. Count:返回集合项数。
  13. Sum:计算序列中的所有数字的和。
  14. Min:返回集合中的最小值。
  15. Max:返回集合中的最大值。
  16. Average:返回集合中的平均值。
  17. Aggregate:传递一个lambda表达式,该表达式对所有的值进行聚合。
  18. Any:确定序列是否包含任何元素。
  19. First:返回序列的第一个元素。
  20. FirstOrDefault:返回序列的第一个元素,如果序列为空则返回默认值。
  21. Last:返回序列的最后一个元素。

此外,还有如TakeTakeWhileSkipSkipWhile等操作符,用于从序列中返回或跳过指定数量的元素。

以上只是LINQ中的一部分操作符,但涵盖了最常用的部分。不同的编程语言可能还提供了额外的LINQ操作符,具体取决于该语言的实现和版本。

二、自定义 LinQ

package com.example.mybatisflexdemo;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class LinqUtils {
    // 类似于LINQ的Where方法
    public static <T> List<T> where(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    // 类似于LINQ的Select方法
    public static <T, R> List<R> select(List<T> list, Function<T, R> mapper) {
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    // 类似于LINQ的FirstOrDefault方法
    public static <T> Optional<T> firstOrDefault(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).findFirst();
    }

    // 类似于LINQ的Any方法
    public static <T> boolean any(List<T> list, Predicate<T> predicate) {
        return list.stream().anyMatch(predicate);
    }

    // 类似于LINQ的All方法
    public static <T> boolean all(List<T> list, Predicate<T> predicate) {
        return list.stream().allMatch(predicate);
    }

    // 示例方法,可以添加更多自定义方法...
    // 统计
    public static <T> Long count(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).count();
    }

    // 模拟LINQ的None
    public static <T> boolean none(List<T> list, Predicate<T> predicate) {
        return list.stream().noneMatch(predicate);
    }

    // 模拟LINQ的First
    public static <T> Optional<T> first(List<T> list) {
        return list.stream().findFirst();
    }

    // 模拟LINQ的FirstOrDefault(需要默认值)
    public static <T> T firstOrDefaultValue(List<T> list, T defaultValue) {
        return list.stream().findFirst().orElse(defaultValue);
    }

    // 模拟LINQ的Last
    public static <T> Optional<T> last(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).reduce((first, second) -> second);
    }
    public static <T> Optional<T> last(List<T> list) {
        return list.stream().reduce((first, second) -> second);
    }

    // 模拟LINQ的LastOrDefault(需要默认值)
    public static <T> T lastOrDefault(List<T> list, T defaultValue) {
        return list.stream().reduce(defaultValue, (a, b) -> b);
    }

    // 模拟LINQ的Take(获取前n个元素)
    public static <T> List<T> take(List<T> list, int n) {
        return list.stream().limit(n).collect(Collectors.toList());
    }

    // 模拟LINQ的Skip(跳过前n个元素)
    public static <T> List<T> skip(List<T> list, int n) {
        return list.stream().skip(n).collect(Collectors.toList());
    }

    // 模拟LINQ的OrderBy(需要额外的比较器)
    public static <T> List<T> orderBy(List<T> list, Comparator<T> comparator) {
        return list.stream()
                .sorted(comparator)
                .collect(Collectors.toList());
    }

    // 模拟LINQ的GroupBy(返回Map)
    public static <T, K> Map<K, List<T>> groupBy(List<T> list, Function<T, K> classifier) {
        return list.stream()
                .collect(Collectors.groupingBy(classifier));
    }

    // 模拟LINQ的Count
    public static long count(List<?> list) {
        return list.stream().count();
    }

    // 模拟LINQ的Sum(假设列表包含数字)
    public static int sum(List<Integer> list) {
        return list.stream()
                .mapToInt(Integer::intValue)
                .sum();
    }

    // 模拟LINQ的Average(假设列表包含数字)
    public static OptionalDouble average(List<Integer> list) {
        return list.stream()
                .mapToDouble(Integer::doubleValue)
                .average();
    }

    // 模拟LINQ的Min(假设列表包含可比较对象)
    public static Optional<Integer> min(List<Integer> list) {
        return list.stream()
                .min(Integer::compareTo);
    }

    // 模拟LINQ的Max(假设列表包含可比较对象)
    public static Optional<Integer> max(List<Integer> list) {
        return list.stream()
                .max(Integer::compareTo);
    }

}

三、测试自定义 LinQ 工具

针对 LINQ 的特点测试了一些常用的接口函数,是的程序写法更加接近 SQL 语法规则。

// 使用示例
public static void main(String[] args) {
    List<Integer> numbers = List.of(1, 2, 3, 4, 5);
    System.out.println("测试初始数据:" + String.join(",", numbers.stream().map(String::valueOf).toList()));
    System.out.println("JDK8统计:" + numbers.stream().filter(i -> i <= 3).count());
    System.out.println("自定义LINQ统计:" + LinqUtils.count(numbers, i -> i <= 3));

    // 使用where方法过滤偶数
    List<Integer> evenNumbers = LinqUtils.where(numbers, n -> n % 2 == 0);
    System.out.println("使用where方法过滤偶数: " + evenNumbers); // 输出: [2, 4]

    // 使用select方法将整数列表转换为字符串列表
    List<String> stringNumbers = LinqUtils.select(numbers, String::valueOf);
    System.out.println("使用select方法将整数列表转换为字符串列表: " + stringNumbers); // 输出: [1, 2, 3, 4, 5]

    // 使用firstOrDefault方法获取第一个偶数,或者为空
    Optional<Integer> firstEven = LinqUtils.firstOrDefault(numbers, n -> n % 2 == 0);
    firstEven.ifPresent(i -> System.out.println("使用firstOrDefault方法获取第一个偶数,或者为空: " + i)); // 输出: 2

    // 使用any方法检查是否有任何偶数大于3
    boolean hasEvenGreaterThan3 = LinqUtils.any(numbers, n -> n > 3 && n % 2 == 0);
    System.out.println("使用any方法检查是否有任何偶数大于3:" + hasEvenGreaterThan3); // 输出: true

    // 使用all方法检查所有数字是否都小于6
    boolean allLessThan6 = LinqUtils.all(numbers, n -> n < 6);
    System.out.println("使用all方法检查所有数字是否都小于6: " + allLessThan6); // 输出: true


    List<Integer> sortedNumbers = orderBy(numbers, Integer::compareTo);
    System.out.println("Sorted numbers: " + sortedNumbers);

    Map<Boolean, List<Integer>> groupedByOddEven = groupBy(numbers, n -> n % 2 == 0);
    System.out.println("Grouped by odd/even: " + groupedByOddEven);

    // 统计元素数量
    long count = count(numbers);
    System.out.println("Count: " + count);

    // 统计 最大值
    int sum = sum(numbers);
    System.out.println("Sum: " + sum);

    // 统计平均值
    OptionalDouble average = average(numbers);
    average.ifPresent(avg -> System.out.println("Average: " + avg));

    // 统计 最小值
    Optional<Integer> min = min(numbers);
    min.ifPresent(m -> System.out.println("Min: " + m));

    // 统计 最大值
    Optional<Integer> max = max(numbers);
    max.ifPresent(m -> System.out.println("Max: " + m));

    // 判断是否: 没有负数吗?
    boolean noneNegative = none(numbers, n -> n < 0);
    System.out.println("Are there no negative numbers? " + noneNegative);

    // 第一个值:
    Optional<Integer> firstNumber = first(numbers);
    firstNumber.ifPresent(n -> System.out.println("First number: " + n));

    // 第一个值or默认值:
    int firstOrDefault = firstOrDefaultValue(numbers, -1);
    System.out.println("FirstOrDefault: " + firstOrDefault);

    // 最后一个值
    Optional<Integer> lastNumber = last(numbers);
    lastNumber.ifPresent(n -> System.out.println("Last number: " + n));

    int lastOrDefault = lastOrDefault(numbers, -1);
    System.out.println("LastOrDefault: " + lastOrDefault);

    List<Integer> firstThree = take(numbers, 3);
    System.out.println("First three numbers: " + firstThree);

    List<Integer> skipFirstThree = skip(numbers, 3);
    System.out.println("Skip first three numbers: " + skipFirstThree);
}

测试结果:

测试初始数据:1,2,3,4,5
JDK8统计:3
自定义LINQ统计:3
使用where方法过滤偶数: [2, 4]
使用select方法将整数列表转换为字符串列表: [1, 2, 3, 4, 5]
使用firstOrDefault方法获取第一个偶数,或者为空: 2
使用any方法检查是否有任何偶数大于3:true
使用all方法检查所有数字是否都小于6: true
Sorted numbers: [1, 2, 3, 4, 5]
Grouped by odd/even: {false=[1, 3, 5], true=[2, 4]}
Count: 5
Sum: 15
Average: 3.0
Min: 1
Max: 5
Are there no negative numbers? true
First number: 1
FirstOrDefault: 1
Last number: 5
LastOrDefault: 5
First three numbers: [1, 2, 3]
Skip first three numbers: [4, 5]

🙏至此,非常感谢阅读🙏