不写 for 循环,
用 SQL 思维
查询内存数据

Linq.J 让 Java 集合查询变得像写 SQL 一样直观。 JOIN、WHERE、GROUP BY、ORDER BY,链式一行搞定,代码即文档。

零外部依赖 50 KB JDK 8+ MIT 开源
QueryDemo.java
LIVE EXAMPLE
// SELECT dept.name, AVG(salary), COUNT(*)
// FROM employees INNER JOIN departments
//   ON dept.id = emp.deptId
// WHERE salary > 5000
// GROUP BY dept.name ORDER BY salary DESC

var result = Linq.from(employees)
    .innerJoin(departments, Dept::getId, Emp::getDeptId)
    .where(Emp::getSalary, salary -> salary > 5000)
    .groupBy(Dept::getName)
    .select(
        Columns.of(Dept::getName, "department"),
        Columns.avg(Emp::getSalary, "avgSalary"),
        Columns.count("headcount")
    )
    .orderByDesc(Emp::getSalary)
    .toList(DeptStats.class);
0
外部依赖
~50KB
体积大小
JDK 8+
最低版本
MIT
开源协议
核心特性

为什么选择 Linq.J?

轻量、强大、优雅 — 用最少的代码完成最复杂的数据查询

零依赖 · 极致轻量

运行时无任何第三方依赖,仅 50KB 大小。引入即用,不会给项目带来任何负担。

类 SQL 链式语法

Select、Join、Where、Group By、Order By、Limit… 用你熟悉的 SQL 思维操作内存数据。

类型安全

基于 Lambda 方法引用的列操作,编译期检查字段名,IDE 自动补全,告别魔法字符串。

多数据源支持

List、Array、SQL 结果集、CSV/JSON/XML、Stream… 任何内存中的集合都能查询。

可插拔查询引擎

抽象 Engine 接口,默认 EruptEngine 内置 Hash Join 等高效策略,可自定义扩展。

丰富的聚合函数

COUNT、SUM、AVG、MAX、MIN、COUNT DISTINCT… 完整的聚合能力,配合 Group By 使用。

操作语法

完整的 SQL 操作对应

Linq.J 提供了与 SQL 一一对应的操作方法,链式调用一气呵成

FROM
→
JOIN
→
WHERE
→
GROUP BY
→
SELECT
→
HAVING
→
ORDER BY
→
LIMIT
→
WRITE
JOIN 关联查询
leftJoin() rightJoin() innerJoin() fullJoin()
WHERE 条件过滤
eq() like() between() in() isNull() gt() / lt() where(λ)
SELECT 投影与聚合
select(Class) select(Field...) count() sum() avg() max() / min()
WRITE 结果写出
toList(Class) one(Class) first(Class) toMaps() toMap() count() exists()
代码示例

直观感受 Linq.J 的优雅

像写 SQL 一样操作 Java 对象,代码即文档

简洁强大的基础查询

从简单的排序过滤到复合操作,一行代码搞定。支持原始类型和自定义对象。

  • 支持原始类型直接查询
  • 链式调用自然流畅
  • 结果自动映射到目标类型
BasicQuery.java
// 字符串排序过滤
var strings = Linq.from("C", "A", "B", "B")
    .gt(It::self, "A")
    .orderByDesc(It::self)
    .toList(String.class);
// 结果: [C, B, B]

// 数字排序
var integers = Linq.from(1, 2, 3, 7, 6, 5)
    .orderBy(It::self)
    .toList(Integer.class);
// 结果: [1, 2, 3, 5, 6, 7]

强大的多表关联

支持四种标准 JOIN 操作,使用 Hash 策略实现高效关联,语法与 SQL 完全对应。

  • LEFT / RIGHT / INNER / FULL JOIN
  • Hash Join 高效引擎
  • Lambda 类型安全关联键
JoinQuery.java
// Left Join + 多表 Select
Linq.from(source)
    .leftJoin(target, Target::getId, Source::getId)
    .select(Source.class)
    .select(Target::getName)
    .toList(Result.class);

// Inner Join + Where + Distinct
var names = Linq.from(data)
    .innerJoin(target, Target::getId, Data::getId)
    .like(Data::getName, "a")
    .select(Data::getName)
    .distinct()
    .orderBy(Data::getName)
    .toList(String.class);

灵活的条件过滤

从简单的等值比较到复杂的自定义条件,WHERE 子句覆盖你的所有需求。

  • eq / between / in / like / isNull
  • 单字段 Lambda 条件
  • 多字段自定义组合条件
WhereQuery.java
// 精确匹配
Linq.from(source).eq(User::getName, "Thanos");

// 范围查询
Linq.from(source).between(User::getId, 1, 100);

// 自定义单字段条件
Linq.from(source).where(User::getId, id -> id >= 5);

// 多字段组合条件
Linq.from(source).where(row -> {
    String name = row.get(User::getName);
    Integer age = (Integer) row.get(User::getAge);
    return "admin".equals(name) || age > 18;
});

分组与聚合

Group By + 聚合函数 + Having,完整的分组聚合能力,生成统计报表轻而易举。

  • GROUP BY 分组
  • HAVING 过滤
  • 多聚合函数组合
GroupByQuery.java
Linq.from(source)
    .groupBy(Order::getCategory)
    .select(
        Columns.of(Order::getCategory, "name"),
        Columns.min(Order::getDate, "earliest"),
        Columns.avg(Order::getPrice, "avgPrice"),
        Columns.count("total"),
        Columns.countDistinct(
            Order::getBuyer, "uniqueBuyers"
        )
    )
    .having(row ->
        Integer.parseInt(
            row.get("total").toString()
        ) > 10
    )
    .orderBy(Order::getPrice)
    .toList(CategoryStats.class);

灵活的结果写出

查询结果可以映射为 Java 对象、List、Map 或单个值,满足不同场景需求。

  • toList() → List<T>
  • one() → T
  • toMaps() → List<Map>
  • toMap() → Map
WriteResult.java
// 写出为对象列表
List<User> list = Linq.from(source)
    .orderByAsc(User::getDate)
    .toList(User.class);

// 写出单个对象
User one = Linq.from(source)
    .limit(1)
    .one(User.class);

// 写出为 Map 列表
List<Map<String, Object>> maps =
    Linq.from(source).toMaps();

// 写出单个 Map
Map<String, Object> map =
    Linq.from(source).toMap();
技术架构

清晰的分层设计

查询构建与执行引擎解耦,接口隔离,灵活可扩展

链式 API 层
Select
Join
Where
GroupBy
OrderBy
Write
↓
查询模型层
Linq (门面)
Dql (查询状态)
Column / Row
↓
执行引擎层
Engine (抽象)
EruptEngine (默认)
Custom Engine
↓
Lambda 解析层
SFunction
LambdaSee
SerializedLambda
应用场景

在哪里使用 Linq.J?

分布式微服务、数据处理、报表生成… 无处不在

01

RPC 结果关联

Feign / Dubbo / gRPC 等微服务调用返回的多个结果集,通过 Linq.J 在内存中进行 JOIN 关联,替代多次数据库查询。

02

异构数据计算

Redis、MongoDB、MySQL 等不同数据源的结果,统一加载到内存后,用 Linq.J 进行跨源查询与聚合。

03

SQL 结果再加工

数据库查询结果需要进一步排序、过滤、聚合?Linq.J 让代码替代复杂的二次 SQL,逻辑清晰可维护。

04

内存分页与排序

多结果合并后的排序聚合与内存分页,告别手写 for 循环和 if 分支,代码量减少 80%。

05

对象转换映射

语义化地完成对象转换与映射,代码即文档,团队协作更清晰敏捷。

06

跨数据源联邦查询

不同系统、不同存储的数据,通过 Linq.J 在应用层实现联邦访问,无需数据迁移。

快速开始

三步上手 Linq.J

零配置,即装即用

01 添加 Maven 依赖
pom.xml
<dependency>
    <groupId>xyz.erupt</groupId>
    <artifactId>linq.j</artifactId>
    <version>${LATEST}</version>
</dependency>
02 确保字段有 Getter
User.java
@Getter  // Lombok 注解
public class User {
    private Long id;
    private String name;
    private Integer age;
}
03 开始查询
Main.java
List<User> adults = Linq.from(users)
    .where(User::getAge, age -> age >= 18)
    .select(User::getName, User::getAge)
    .orderBy(User::getAge)
    .toList(User.class);
对比

传统写法 vs Linq.J

传统 Java 写法
Traditional.java
Map<String, List<Order>> grouped = new HashMap<>();
for (Order o : orders) {
    if (o.getAmount() > 100) {
        grouped.computeIfAbsent(
            o.getCategory(),
            k -> new ArrayList<>()
        ).add(o);
    }
}
Map<String, Double> avgMap = new HashMap<>();
for (var entry : grouped.entrySet()) {
    double sum = 0;
    for (var o : entry.getValue()) {
        sum += o.getAmount();
    }
    avgMap.put(entry.getKey(),
        sum / entry.getValue().size());
}
// 还需要排序... 更多代码...
VS
Linq.J 写法
LinqWay.java
var result = Linq.from(orders)
    .where(Order::getAmount,
        a -> a > 100)
    .groupBy(Order::getCategory)
    .select(
        Columns.of(Order::getCategory, "cat"),
        Columns.avg(Order::getAmount, "avg"),
        Columns.count("cnt")
    )
    .orderByDesc(Order::getAmount)
    .toList(Stats.class);

// 清晰 · 简洁 · 高效
路线图

持续进化中

Linq.J 正在不断完善,更多强大特性即将到来

已完成

HAVING 支持

分组聚合后的条件过滤

已完成

分组列格式化

支持 group by date(created_at) 等表达式

计划中

集合操作

UNION ALL、UNION、INTERSECT、EXCEPT、UNION BY NAME

计划中

窗口函数

ROW_NUMBER、RANK、DENSE_RANK 等分析函数