1. 简介

LangChain4j 是一个基于 Java 的开源框架,用于开发 人工智能驱动的应用程序,尤其是涉及 大语言模型(LLM)交互 的场景。它的设计目标是简化开发者与大语言模型的集成过程,提供一套工具和组件来处理复杂的 LLM 应用逻辑,例如对话管理、提示工程、工具调用等。

核心功能与特点

  1. 大语言模型集成

    • 支持多种 LLM 接入方式,包括:

      • 本地运行的开源模型(如 Llama 2、ChatGLM 等)。
      • 第三方 API 模型(如 OpenAI 的 GPT 系列、Anthropic 的 Claude 等)。
    • 通过统一的接口抽象,降低模型切换的成本。
  2. 提示工程工具
    • 提供模板化的提示构建器,帮助开发者结构化输入(如填充变量、管理上下文历史)。
    • 支持动态组合提示链(Prompt Chain),例如根据用户问题逐步调用不同的提示模板。
  3. 对话状态管理
    • 维护多轮对话的上下文,支持记忆管理(如设置上下文窗口大小、选择性遗忘旧信息)。
    • 可集成外部知识库(如向量数据库)实现长期记忆。
  4. 工具调用能力
    • 支持调用外部工具(如计算器、数据库查询、API 接口等),并将工具返回结果整合到 LLM 的回答中。
    • 提供工具调用的决策逻辑(如判断何时需要调用工具、如何解析工具返回结果)。
  5. 链式流程编排
    • 通过 Chain 机制编排多个组件(如提示生成、工具调用、结果处理),形成复杂的工作流。
    • 典型场景:问答系统中先调用搜索引擎获取实时数据,再用 LLM 生成回答。
  6. 扩展性与生态
    • 基于 Java 生态,可轻松与 Spring框架集成。
    • 支持自定义组件(如自定义提示策略、工具适配器),灵活适配业务需求。

2. 话不多说,直接展示

本章主要通过单元测试的方式展示LangChain4j的各项功能,后续会出通过LangChain4j Starter的方式快速集成SpringBoot。

使用SDK版本信息如下:

​ Java: 21

​ SpringBoot: 3.4.5

​ LangChain4j: 1.0.1

AI 模型主要使用的是阿里的百炼平台免费的token,需要ApiKey的可以自行去申请, 平台地址如下:

https://bailian.console.aliyun.com/?tab=model#/model-market

3. Maven

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>langchain-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>langchain-test</name>
<description>langchain-test</description> <properties>
<java.version>21</java.version>
<langchain4j.version>1.0.1</langchain4j.version>
<guava.version>33.0.0-jre</guava.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>${langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency> <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency> <dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency> <dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

4. 构建模型对象

// 普通的对话模型
private static ChatModel chatModel; // 流式对话的模型(可以模拟gpt的打字机效果)
private static StreamingChatModel streamingChatModel; @BeforeAll
public static void init_chat_model() {
chatModel = OpenAiChatModel
.builder()
// apikey 通过环境变量的方式注入,大家可以使用自己的apikey
.apiKey(System.getenv("LLM_API_KEY"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
streamingChatModel = OpenAiStreamingChatModel
.builder()
.apiKey(System.getenv("LLM_API_KEY"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}

5. 返回字符串

@Test
public void should_return_str_when_use_normal_chat() {
String q = "你是谁";
String content = chatModel.chat(q);
log.info("call ai q: {}\na: {}", q, content);
}

测试结果如下:

22:12:37.807 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q: 你是谁
a: 我是通义千问,阿里巴巴集团旗下的超大规模语言模型。我能够回答问题、创作文字,比如写故事、公文、邮件、剧本等,还能进行逻辑推理、编程,甚至表达观点和玩游戏。我在多国语言上都有很好的掌握,能为你提供多样化的帮助。有什么我可以帮到你的吗?

6. 返回流

这里使用flux对象接收流式返回的结果

如果想流式的返回给前端,也可以使用SSE的方式返回(代码注释的部分)

@Test
public void should_return_stream_when_use_stream_model() {
Sinks.Many<String> sinks = Sinks
.many()
.multicast()
.onBackpressureBuffer();
Flux<String> flux = sinks.asFlux();
StreamingChatResponseHandler streamingChatResponseHandler = new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String s) {
sinks.tryEmitNext(s);
} @Override
public void onCompleteResponse(ChatResponse chatResponse) {
sinks.tryEmitComplete();
} @Override
public void onError(Throwable throwable) {
sinks.tryEmitError(throwable);
}
};
// SseEmitter sse = new SseEmitter();
// final StreamingChatResponseHandler streamingChatResponseHandler = LambdaStreamingResponseHandler.onPartialResponseAndError(s -> {
// try {
// log.info("ai response stream data: {}", s);
// sse.send(s);
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// }, e -> sse.complete());
streamingChatModel.chat("你是谁", streamingChatResponseHandler);
flux
.toStream()
.forEach(partial -> log.info("ai response stream data: {}", partial));
}

测试结果如下:

22:45:26.442 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 我是
22:45:26.444 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 通
22:45:26.444 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 义
22:45:26.541 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 千问,阿里巴巴
22:45:26.771 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 集团旗下的通义
22:45:26.790 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 实验室自主研发的超
22:45:26.949 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 大规模语言模型。
22:45:27.103 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 我能够回答问题
22:45:27.199 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 、创作文字,
22:45:27.320 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 比如写故事、
22:45:27.482 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 写公文、
22:45:27.586 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 写邮件、写
22:45:27.789 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 剧本、逻辑推理
22:45:27.863 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 、编程等等,
22:45:27.982 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 还能表达观点,
22:45:28.435 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 玩游戏等。如果你
22:45:28.453 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 有任何问题或需要
22:45:28.576 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 帮助,欢迎随时
22:45:28.665 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ai response stream data: 告诉我!

7. 提示词/模板

@Test
public void should_return_prompt_content_when_use_prompt() {
// 申明系统提示词
// SystemMessage systemMessage = Prompt.from("你是一名java专家,请协助用户解决相应的专业性问题").toSystemMessage();
// 申明提示词模板
final PromptTemplate promptTemplate = new PromptTemplate("""
将文本改写成类似小红书的 Emoji 风格。
请使用 Emoji 风格编辑以下段落,该风格以引人入胜的标题、每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。
用户的提问信息如下:
{{question}}
""");
final UserMessage userMessage = promptTemplate
.apply(Map.of("question", "你是谁"))
.toUserMessage();
ChatResponse chatResponse = chatModel.chat(userMessage);
String content = chatResponse
.aiMessage()
.text();
log.info("call ai q: {}\na: {}", userMessage.singleText(), content);
}

测试结果如下:

22:46:36.572 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q:  将文本改写成类似小红书的 Emoji 风格。
请使用 Emoji 风格编辑以下段落,该风格以引人入胜的标题、每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。
用户的提问信息如下:
你是谁 a: 你是谁?来认识一下我吧! 嗨,亲爱的朋友们!我是通义千问,阿里巴巴集团旗下的超大规模语言模型。我可以通过学习海量文本数据,帮你回答问题、创作文字,甚至玩游戏哦~是不是很酷呢? 如果你有任何问题或需要帮助,尽管告诉我!我会尽力为你提供支持和支持️。让我们一起开启有趣的探索之旅吧! #人工智能 #聊天机器人 #新知探索 #科技生活

8. 聊天记忆

中心逻辑其实就是:将最近的聊天内容存储起来,然后一股脑扔给AI

@Test
public void should_return_memory_content_when_use_memory_chat() {
String id = "zhangtieniu_01";
String q1 = "你是谁";
ChatMemory chatMemory = MessageWindowChatMemory
.builder()
// 会话隔离(不同用户的聊天信息互不干扰)
.id(id)
// 最大存储最近的5条聊天内容(存储太多影响性能&token)
.maxMessages(5)
.build();
// 将聊天内容放入记忆对象中
chatMemory.add(UserMessage.from(q1));
// SystemMessage 始终保存在messages中 且占用maxMessage名额
chatMemory.add(SystemMessage.from("""
将文本改写成类似小红书的 Emoji 风格。
请使用 Emoji 风格编辑以下段落,该风格以引人入胜的标题、每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。
"""));
final ChatResponse chatResponse = chatModel.chat(chatMemory.messages());
// 将ai的返回结果放入记忆对象中
chatMemory.add(chatResponse.aiMessage());
String q2 = "我刚刚问了啥";
chatMemory.add(UserMessage.from(q2));
final ChatResponse chatResponse2 = chatModel.chat(chatMemory.messages()); log.info("call ai q1: {}\na1: {}", q1, chatResponse
.aiMessage()
.text());
log.info("==========================分隔符==========================");
log.info("call ai q2: {}\na2: {}", q2, chatResponse2
.aiMessage()
.text());
}

测试结果如下:

22:54:58.965 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q1: 你是谁
a1: 你好呀,让我来介绍一下自己! 我是通义千问,阿里巴巴集团旗下的超大规模语言模型。我不仅能陪你聊天,还能帮你写故事、邮件、剧本等等,甚至可以表达观点、玩游戏呢! 无论你想聊生活中的小确幸 还是工作学习中的难题 ,我都会尽力帮助你!希望我能成为你的贴心小伙伴~ ️ #人工智能 #聊天伙伴 #创作助手 #日常分享
22:54:58.968 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- ==========================分隔符==========================
22:54:58.969 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q2: 我刚刚问了啥
a2: 呃... 让我查查!哦对!你刚刚问的是:“我是谁?” 这个问题让我有机会用小红书风格重新介绍自己呢! 作为通义千问,我最喜欢的就是通过对话帮助别人啦!如果你还有其他问题或者需要灵感,随时可以问我哦~ #回忆对话 #人工智能 #问答时间 #互动分享

9. 聊天内容持久化

9.1 store handler

这里简单的使用map存储会话内容

package com.ldx.langchaintest.store;

import com.google.common.collect.ArrayListMultimap;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.store.memory.chat.ChatMemoryStore; import java.util.List; public class PersistentChatMemoryStoreTest implements ChatMemoryStore {
public final ArrayListMultimap<Object, ChatMessage> messagesStore = ArrayListMultimap.create(); @Override
public List<ChatMessage> getMessages(Object memoryId) {
return messagesStore.get(memoryId);
} @Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
messagesStore.put(memoryId, messages.getLast());
} @Override
public void deleteMessages(Object memoryId) {
messagesStore.removeAll(memoryId);
}
}

9.2 实现

@Test
public void should_return_memory_content_when_use_store_chat() {
String id = "zhangtieniu_01";
String q1 = "张铁牛是一个高富帅,你是张铁牛的助手";
PersistentChatMemoryStoreTest store = new PersistentChatMemoryStoreTest();
ChatMemory chatMemory = MessageWindowChatMemory
.builder()
.id(id)
.chatMemoryStore(store)
.maxMessages(5)
.build();
chatMemory.add(UserMessage.from(q1));
final ChatResponse chatResponse = chatModel.chat(chatMemory.messages());
chatMemory.add(chatResponse.aiMessage());
String q2 = "张铁牛是谁";
chatMemory.add(UserMessage.from(q2));
final ChatResponse chatResponse2 = chatModel.chat(chatMemory.messages());
chatMemory.add(chatResponse2.aiMessage()); // 获取当前会话的存储内容并打印
List<ChatMessage> chatMessages = store.messagesStore.get(id);
for (ChatMessage chatMessage : chatMessages) {
log.info("session id: {}, message type: {}, message: {}", id, chatMessage.type(), chatMessage);
}
}

测试结果如下:

23:09:08.086 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- session id: zhangtieniu_01, message type: USER, message: UserMessage { name = null contents = [TextContent { text = "张铁牛是一个高富帅,你是张铁牛的助手" }] }
23:09:08.089 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- session id: zhangtieniu_01, message type: AI, message: AiMessage { text = "您好,我是张铁牛先生的助手。张铁牛先生确实是一位优秀的人士,他不仅外貌出众、家境优渥,而且非常有才华。作为他的助手,我会帮助他处理各种事务,确保他的生活和工作都井井有条。如果您有任何需要帮忙的事情,或者想了解张铁牛先生的相关信息,只要是我职责范围内的,我都会尽力提供帮助。请问有什么我可以为您服务的呢?" toolExecutionRequests = [] }
23:09:08.090 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- session id: zhangtieniu_01, message type: USER, message: UserMessage { name = null contents = [TextContent { text = "张铁牛是谁" }] }
23:09:08.090 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- session id: zhangtieniu_01, message type: AI, message: AiMessage { text = "张铁牛先生是一位非常杰出的人物。他出身于一个成功的企业家庭,拥有优越的教育资源和广泛的商业人脉。除了在商业领域的卓越成就外,他还以阳光、正直的形象受到周围人的喜爱。 作为一位“高富帅”,张铁牛先生不仅注重个人修养,还热衷于公益事业,经常参与慈善活动来回馈社会。同时,他对生活充满热情,兴趣爱好广泛,比如健身、旅行以及收藏艺术品等。 不过,请允许我提醒您,虽然他是公众眼中的完美人物,但他更希望被当作普通人来尊重,注重隐私保护。如果您有关于他的正面问题或需要安排相关事务,我很乐意为您提供帮助!" toolExecutionRequests = [] }

10. function call

10.1 user svc

声明一个自定义的user svc, 让ai去调用我们的业务方法

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool; public class UserServiceTest {
@Tool("根据用户的名称获取对应的code")
public String getUserCodeByUsername(@P("用户名称") String username) {
if ("张铁牛".equals(username)) {
return "003";
} return "000";
}
}

10.2 实现

@Test
public void should_return_func_content_when_use_function_call() {
final String q = "张铁牛的code是多少";
List<ChatMessage> chatMessages = new ArrayList<>();
chatMessages.add(UserMessage.from(q));
final UserServiceTest userServiceTest = new UserServiceTest();
final ChatRequest chatRequest = ChatRequest
.builder()
.messages(UserMessage.from(q))
// 将工具类注入到上下文中
.toolSpecifications(ToolSpecifications.toolSpecificationsFrom(userServiceTest))
.build();
final ChatResponse chatResponse = chatModel.chat(chatRequest);
final AiMessage aiMessage = chatResponse.aiMessage();
chatMessages.add(aiMessage);
String a = aiMessage.text(); // 在响应结果中判断是否有tool请求
if (aiMessage.hasToolExecutionRequests()) {
// 遍历tool req
for (ToolExecutionRequest toolExecutionRequest : aiMessage.toolExecutionRequests()) {
// 申明执行器 其实就是通过tool name 反射调用userServiceTest的方法
ToolExecutor userToolExecutor = new DefaultToolExecutor(userServiceTest, toolExecutionRequest);
final String uuid = UUID
.randomUUID()
.toString();
final String executeResult = userToolExecutor.execute(toolExecutionRequest, uuid);
log.info("execute user tool, name: {}, param:{}, result: {} ", toolExecutionRequest.name(), toolExecutionRequest.arguments(), executeResult);
final ToolExecutionResultMessage toolExecutionResultMessages = ToolExecutionResultMessage.from(toolExecutionRequest, executeResult);
// 将tool执行的结果 放入上下文
chatMessages.add(toolExecutionResultMessages);
}
// 再次请求ai
a = chatModel
.chat(chatMessages)
.aiMessage()
.text();
} log.info("call ai q:{}\na:{}", q, a);
}

测试结果如下:

23:18:53.710 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- execute user tool, name: getUserCodeByUsername, param:{"username": "张铁牛"}, result: 003
23:18:55.482 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q:张铁牛的code是多少
a:根据您的问题,张铁牛的代码是 **003**。如果还有其他相关信息需要补充或查询,请告诉我!

11. dynamic function call

因为有的时候我们使用已有的svc时,我们可能无法直接给目标方法标注对应的注解让AI来识别方法(比如第三方包里的方法)

所以就需要动态的创建tool的描述类,如下

@Test
public void should_return_func_content_when_use_dynamic_function_call() {
final String q = "张铁牛的code是多少";
final List<ChatMessage> chatMessages = new ArrayList<>();
chatMessages.add(UserMessage.from(q));
final UserServiceTest userServiceTest = new UserServiceTest();
final ToolSpecification toolSpecification = ToolSpecification
.builder()
.name("getUserCodeByUsername")
.description("根据用户的名称获取对应的code")
.parameters(JsonObjectSchema
.builder()
.addStringProperty("username", "用户姓名")
.build())
.build(); final ChatRequest chatRequest = ChatRequest
.builder()
.messages(UserMessage.from(q))
.toolSpecifications(toolSpecification)
.build();
final ChatResponse chatResponse = chatModel.chat(chatRequest);
AiMessage aiMessage = chatResponse.aiMessage();
chatMessages.add(aiMessage);
String a = aiMessage.text(); if (aiMessage.hasToolExecutionRequests()) {
for (ToolExecutionRequest toolExecutionRequest : aiMessage.toolExecutionRequests()) {
ToolExecutor userToolExecutor = new DefaultToolExecutor(userServiceTest, toolExecutionRequest);
final String uuid = UUID
.randomUUID()
.toString();
final String executeResult = userToolExecutor.execute(toolExecutionRequest, uuid);
log.info("execute user tool, name: {}, param:{}, result: {} ", toolExecutionRequest.name(), toolExecutionRequest.arguments(), executeResult);
final ToolExecutionResultMessage toolExecutionResultMessages = ToolExecutionResultMessage.from(toolExecutionRequest, executeResult);
chatMessages.add(toolExecutionResultMessages);
} a = chatModel
.chat(chatMessages)
.aiMessage()
.text();
} log.info("call ai q:{}\na:{}", q, a);
}

测试结果如下:

23:22:53.626 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- execute user tool, name: getUserCodeByUsername, param:{"username": "张铁牛"}, result: 003
23:22:55.065 [main] INFO com.ldx.langchaintest.lowapi.AiChatTest -- call ai q:张铁牛的code是多少
a:根据您的问题,张铁牛的代码是 **003**。如果还有其他相关信息需要补充,请告诉我!

12. 小结

本章使用了LangChain4j一些比较底层的(原生的)api来请求大模型, 展示了AI服务中常见的使用方法,下一章我们将使用LangChain4jAI Service功能来展示LangChain4j高阶用法。

1. LangChain4j 初识,想使用Java开发AI应用?的更多相关文章

  1. Java开发和运行环境的搭建

    Java开发需要准备的东西? JDK+Eclipse 其中JDK的意思是Java开发工具包,Eclipse是进行用于做Java程序开发的工具(当然你也可以用记事本什么的去做). 其他开发工具:JCre ...

  2. 媳妇要转java开发,我该怎么办?

    我是一名5年的java开发者,媳妇是一个5年的软件实施工程师,我们结婚快一年了,这几天她突然对我说,她想转java开发,让我辅导她学习java,我该怎么弄,我心底是不愿意她转开发的,毕竟她年龄也不小了 ...

  3. Java开发微信公众号(一)---初识微信公众号以及环境搭建

    ps:1.开发语言使用Java springMvc+Mybaits+spring maven实现 2.使用微信接口测试账号进行本地测试 https://mp.weixin.qq.com/debug/c ...

  4. 面试大厂回来后,有一些话想对 Java 后端开发说一说

    在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间.我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面 ...

  5. 《码出高效:Java开发手册》第四章学习记录,内容想当的多,前后花了几天的时间才整理好。

    <码出高效:Java开发手册>第四章学习记录,内容想当的多,前后花了几天的时间才整理好. https://naotu.baidu.com/file/e667435a4638cbaa15eb ...

  6. 006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序

    006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序 Eclipse下创建程序 创建程序分为以下几个步骤: 1.首先是创建一个 ...

  7. java开发初识

    jdk目录相关介绍: bin:存放的是java的相关开发工具 db:顾名思义jre附带的轻量级数据库 include:存放的是调用系统资源的接口文件 jre:java的运行环境 lib:核心的类库 s ...

  8. 初识Java以及JAVA开发环境搭建

    目录 JAVA帝国的诞生 C&C++ JAVA JAVA特性和优势 JAVA三大版本 JDK.JRE.JVE JAVA开发环境搭建 JDK下载与安装.卸载 安装JDK 卸载JDK JDK目录介 ...

  9. Java开发环境的配置与Hello World

    一.Java开发需要做的准备 Java程序的执行过程是首先由Java编译器将以.java为后缀的Java源文件编译成.class字节码文件.然后字节码文件便可以由JVM虚拟机进行加载并执行. 在初学J ...

  10. 阿里巴巴Java开发手册(详尽版)-个人未注意到的知识点(转)

    转自 https://blog.csdn.net/u013039395/article/details/86528164 一.编程规约 (一) 命名风格 [强制]代码中的命名只可用英文方式 [强制]类 ...

随机推荐

  1. Font-awesome失效恢复

    Font-awesome失效恢复策略 可能的原因有: 1.用了收费pro的版本,没充钱. Font Awesome 6 字体分为 Free 和 Pro 两个版本.Font Awesome 6 Free ...

  2. 解决vscode"无法加载文件 ,因为在此系统上禁止运行脚本"报错

    问题 在使用 vscode 自带程序终端时,会报"无法加载文件 ,因为在此系统上禁止运行脚本",这是因为 PowerShell 执行策略的问题. > tsc --init t ...

  3. ubuntu网络连接失败

    首先要保证pc上可以连接上网络,然后进行下面的操作: 1.首先选择VMware的编辑选项 2.选择虚拟网络编辑器 3.还原默认设置,等待几分钟,确定就可以解决了

  4. SpringBoot集成LDAP认证登录

    Maven依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  5. [源码系列:手写spring] IOC第七节:加载xml文件中定义的Bean

    目录 主要内容 代码分支 核心代码 BeanDefinitionReader AbstractBeanDefinitionReader XmlBeanDefinitionReader 测试 bean定 ...

  6. 2025成都.NET开发者Connect圆满结束

    大家好,我是Edison. 2025年成都.NET开发者Connect线下聚会活动于3月29日圆满结束,本次活动吸引了约30位.NET开发者朋友参与,他们分别来自成都各家技术公司,我们相聚城南华府国际 ...

  7. study Python3【3】的函数

    Python的函数定义简单,但灵活度非常大.功能强大意味复杂.为了复习,把廖雪峰老师的该课程做个回顾. 参数有:必选参数.默认参数.可变参数.关键字参数.命名关键字参数. 计算x的n次方函数: def ...

  8. Readers and Writers JSON Framework(2)

    我们关心json的读写.特别在datasnap中,关于使用stream更是显得重要.其实轮子都帮你做好了,你不知道整经再研究就是一个悲哀.除非你要研究. 回正题: 处理json有二套框架. JSON ...

  9. Rabbitmq防止消息的丢失

    一.Rabbitmq的流程图 二.出现消息丢失的三个可能 A:写消息的过程,消息都没到rabbitmq,在网络传输过程就丢了:或者是消息到了rabbitmq,但是人家内部出错了没保存下来 例子: 1. ...

  10. 关于TCP的握手与挥手

    关于TCP的握手与挥手 前言 由于自己每次都是唱的比懂的好听,光知道唱"三次握手四次挥手",再往里细问SYN标志就只能阿巴阿巴阿巴,为了解决自己的知识储备问题,顺便继续深入了解TC ...