java 有限状态机_有限状态机的4种Java实现对比

2023-11-08

写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下!

GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master

在日常工作过程中,我们经常会遇到状态的变化场景,例如订单状态发生变化,商品状态的变化。这些状态的变化,我们称为有限状态机,缩写为FSM( F State Machine).。之所以称其为有限,是因为这些场景中的状态往往是可以枚举出来的有限个的,所以称其为有限状态机。下面我们来看一个具体的场景例子。

简单场景:

地铁进站闸口的状态有两个:已经关闭、已经开启两个状态。刷卡后闸口从已关闭变为已开启,人通过后闸口状态从已开启变为已关闭。

01 遇到这类问题,在编码时我们应该如何处理呢?

基于Switch

基于状态集合

基于State模式

基于枚举的实现

下面我们针对每一种实现方式进行分析。场景分解后会有一下2种状态4种情况出现:

fe05e3b1ae66

image.png

针对以上4种请求,共拆分了5个Test Case

T01

Given:一个Locked的进站闸口

When: 投入硬币

Then:打开闸口

T02

Given:一个Locked的进站闸口

When: 通过闸口

Then:警告提示

T03

Given:一个Unocked的进站闸口

When: 通过闸口

Then:闸口关闭

T04

Given:一个Unlocked的进站闸口

When: 投入硬币

Then:退还硬币

T05

Given:一个闸机口

When: 非法操作

Then:操作失败

项目中共有4中状态机的实现方式。

基于Switch语句实现的有限状态机,代码在 master 分支

基于State模式实现的有限状态机。代码在 state-pattern 分支

基于状态集合实现的有限状态机。代码在 collection-state 分支

基于枚举实现的状态机。代码在 enum-state 分支

01.01 使用Switch来实现有限状态机

这种方式只需要懂得Java语法及可以实现出来。先看代码,然后我们在讨论这种实现方式是否好。

EntranceMachineTest.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import static org.assertj.core.api.BDDAssertions.then;

class EntranceMachineTest {

@Test

void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("opened");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

@Test

void should_be_locked_and_alarm_when_pass_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("alarm");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

@Test

void should_fail_when_execute_invalid_action_given_a_entrance_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

assertThatThrownBy(() -> entranceMachine.execute(null))

.isInstanceOf(InvalidActionException.class);

}

@Test

void should_locked_when_pass_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("closed");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

@Test

void should_refund_and_unlocked_when_insert_coin_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("refund");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

}

Action.java

public enum Action {

INSERT_COIN,

PASS

}

EntranceMachineState.java

public enum EntranceMachineState {

UNLOCKED,

LOCKED

}

InvalidActionException.java

package com.page.java.fsm.exception;

public class InvalidActionException extends RuntimeException {

}

EntranceMachine.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import lombok.Data;

import java.util.Objects;

@Data

public class EntranceMachine {

private EntranceMachineState state;

public EntranceMachine(EntranceMachineState state) {

this.state = state;

}

public String execute(Action action) {

if (Objects.isNull(action)) {

throw new InvalidActionException();

}

if (EntranceMachineState.LOCKED.equals(state)) {

switch (action) {

case INSERT_COIN:

setState(EntranceMachineState.UNLOCKED);

return open();

case PASS:

return alarm();

}

}

if (EntranceMachineState.UNLOCKED.equals(state)) {

switch (action) {

case PASS:

setState(EntranceMachineState.LOCKED);

return close();

case INSERT_COIN:

return refund();

}

}

return null;

}

private String refund() {

return "refund";

}

private String close() {

return "closed";

}

private String alarm() {

return "alarm";

}

private String open() {

return "opened";

}

}

if(), swich语句都是switch语句,但是 Switch是一种Code Bad Smell ,因为它本质上一种重复。当代码中有多处相同的switch时,会让系统变得晦涩难懂,脆弱,不易修改。

上面的代码虽然出现了多层嵌套但是还算是结构简单,不过想通过并不能很清楚闸机口的逻辑还是化点时间。如果闸机口的状态等多一些,那就阅读、理解起来也就更加困难。

所以在日常工作,我遵循“事不过三,三则重构”的原则:

事不过三:

当只有一两个状态(或者重复)时,那么先用最简单的实现实现。

一旦出现三种以及以上的状态(或者重复),立即重构。

01.02 State模式

EntranceMachineTest.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import static org.assertj.core.api.BDDAssertions.then;

class EntranceMachineTest {

@Test

void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(new LockedEntranceMachineState());

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("opened");

then(entranceMachine.isUnlocked()).isTrue();

}

@Test

void should_be_locked_and_alarm_when_pass_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(new LockedEntranceMachineState());

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("alarm");

then(entranceMachine.isLocked()).isTrue();

}

@Test

void should_fail_when_execute_invalid_action_given_a_entrance_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(new LockedEntranceMachineState());

assertThatThrownBy(() -> entranceMachine.execute(null))

.isInstanceOf(InvalidActionException.class);

}

@Test

void should_locked_when_pass_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(new UnlockedEntranceMachineState());

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("closed");

then(entranceMachine.isLocked()).isTrue();

}

@Test

void should_refund_and_unlocked_when_insert_coin_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(new UnlockedEntranceMachineState());

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("refund");

then(entranceMachine.isUnlocked()).isTrue();

}

}

EntranceMachineState.java

package com.page.java.fsm;

public interface EntranceMachineState {

String insertCoin(EntranceMachine entranceMachine);

String pass(EntranceMachine entranceMachine);

}

LockedEntranceMachineState.java

package com.page.java.fsm;

public class LockedEntranceMachineState implements EntranceMachineState {

@Override

public String insertCoin(EntranceMachine entranceMachine) {

return entranceMachine.open();

}

@Override

public String pass(EntranceMachine entranceMachine) {

return entranceMachine.alarm();

}

}

UnlockedEntranceMachineState.java

package com.page.java.fsm;

public class UnlockedEntranceMachineState implements EntranceMachineState {

@Override

public String insertCoin(EntranceMachine entranceMachine) {

return entranceMachine.refund();

}

@Override

public String pass(EntranceMachine entranceMachine) {

return entranceMachine.close();

}

}

Action.java

package com.page.java.fsm;

public enum Action {

PASS,

INSERT_COIN

}

EntranceMachine.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import java.util.Objects;

public class EntranceMachine {

private EntranceMachineState locked = new LockedEntranceMachineState();

private EntranceMachineState unlocked = new UnlockedEntranceMachineState();

private EntranceMachineState state;

public EntranceMachine(EntranceMachineState state) {

this.state = state;

}

public String execute(Action action) {

if (Objects.isNull(action)) {

throw new InvalidActionException();

}

if (Action.PASS.equals(action)) {

return state.pass(this);

}

return state.insertCoin(this);

}

public boolean isUnlocked() {

return state == unlocked;

}

public boolean isLocked() {

return state == locked;

}

public String open() {

setState(unlocked);

return "opened";

}

public String alarm() {

setState(locked);

return "alarm";

}

public String refund() {

setState(unlocked);

return "refund";

}

public String close() {

setState(locked);

return "closed";

}

private void setState(EntranceMachineState state) {

this.state = state;

}

}

State模式和Proxy模式类似,但是在State模式中EntranceMachineState持有EntranceMachine实例的引用。

我们发现EntranceMachine的execute()方法的逻辑变的简单,但是代码复杂度升高了。因为每个state实例都提供了两个动作实现insertCoin()和pass()。这个地方本人认为并不够表意,因为作出的动作被添加到两个状态上,虽然能够实现业务业务,但是并不利于理解清楚业务意思。

State模式,虽然能够将逻辑进行拆分,但是那些状态的顺序,以及有几种状态,都不是很直观的观察到。

不过在实际业务中,State模式也是一种很好的实现方式,毕竟他避免了switch的堆积问题。

01.03 使用状态集合

状态集合是将一组描述状态变化的事务元素组成的集合。

集合中的每一个元素包含4个属性:当前的状态,事件,下一个状态,触发的动作。

使用时遍历集合根据动作找到特定的元素,并更具元素上的属性和事件来完成业务逻辑。

具体代码如下:

EntranceMachineTest.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import static org.assertj.core.api.BDDAssertions.then;

class EntranceMachineTest {

@Test

void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("opened");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

@Test

void should_be_alarm_when_pass_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("alarm");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

@Test

void should_fail_when_execute_invalid_action_given_a_entrance_machine() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

assertThatThrownBy(() -> entranceMachine.execute(null))

.isInstanceOf(InvalidActionException.class);

}

@Test

void should_closed_when_pass_given_a_entrance_machine_with_unlocked() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("closed");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

@Test

void should_refund_when_insert_coin_given_a_entrance_machine_with_unlocked() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("refund");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

}

Action.java

package com.page.java.fsm;

public enum Action {

PASS,

INSERT_COIN

}

EntranceMachineState.java

package com.page.java.fsm;

public enum EntranceMachineState {

LOCKED,

UNLOCKED

}

EntranceMachine.java

package com.page.java.fsm;

import com.page.java.fsm.events.AlarmEvent;

import com.page.java.fsm.events.CloseEvent;

import com.page.java.fsm.events.OpenEvent;

import com.page.java.fsm.events.RefundEvent;

import com.page.java.fsm.exception.InvalidActionException;

import lombok.Data;

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

@Data

public class EntranceMachine {

List entranceMachineTransactionList = Arrays.asList(

EntranceMachineTransaction.builder()

.currentState(EntranceMachineState.LOCKED)

.action(Action.INSERT_COIN)

.nextState(EntranceMachineState.UNLOCKED)

.event(new OpenEvent())

.build(),

EntranceMachineTransaction.builder()

.currentState(EntranceMachineState.LOCKED)

.action(Action.PASS)

.nextState(EntranceMachineState.LOCKED)

.event(new AlarmEvent())

.build(),

EntranceMachineTransaction.builder()

.currentState(EntranceMachineState.UNLOCKED)

.action(Action.PASS)

.nextState(EntranceMachineState.LOCKED)

.event(new CloseEvent())

.build(),

EntranceMachineTransaction.builder()

.currentState(EntranceMachineState.UNLOCKED)

.action(Action.INSERT_COIN)

.nextState(EntranceMachineState.UNLOCKED)

.event(new RefundEvent())

.build()

);

private EntranceMachineState state;

public EntranceMachine(EntranceMachineState state) {

setState(state);

}

public String execute(Action action) {

Optional transactionOptional = entranceMachineTransactionList

.stream()

.filter(transaction ->

transaction.getAction().equals(action) && transaction.getCurrentState().equals(state))

.findFirst();

if (!transactionOptional.isPresent()) {

throw new InvalidActionException();

}

EntranceMachineTransaction transaction = transactionOptional.get();

setState(transaction.getNextState());

return transaction.getEvent().execute();

}

}

EntranceMachineTransaction.java

package com.page.java.fsm;

import com.page.java.fsm.events.Event;

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

@Data

@Builder

@NoArgsConstructor

@AllArgsConstructor

public class EntranceMachineTransaction {

private EntranceMachineState currentState;

private Action action;

private EntranceMachineState nextState;

private Event event;

}

Event.java

package com.page.java.fsm.events;

public interface Event {

String execute();

}

OpenEvent.java

package com.page.java.fsm.events;

public class OpenEvent implements Event {

@Override

public String execute() {

return "opened";

}

}

AlarmEvent.java

package com.page.java.fsm.events;

public class AlarmEvent implements Event {

@Override

public String execute() {

return "alarm";

}

}

CloseEvent.java

package com.page.java.fsm.events;

public class CloseEvent implements Event {

@Override

public String execute() {

return "closed";

}

}

RefundEvent.java

package com.page.java.fsm.events;

public class RefundEvent implements Event {

@Override

public String execute() {

return "refund";

}

}

InvalidActionException.java

package com.page.java.fsm.exception;

public class InvalidActionException extends RuntimeException {

}

相比于Switch的实现方式,状态集合的实现方式对状态规则的描述更加直观。且扩展性更强,不需求修改实现路基,只需要添加相关的状态描述即可。

我们知道日常工作中读代码和写代码比例在10:1,有些场景下甚至到了20:1。Switch需要我们每次在脑子中组织一次状态的顺序和规则,而集合能够很直观的表达出这个规则。

01.04 使用Enum的来实现状态机

EntranceMachineTest.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import static org.assertj.core.api.BDDAssertions.then;

class EntranceMachineTest {

@Test

void should_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("opened");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

@Test

void should_alarm_when_pass_given_a_entrance_machine_with_locked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("alarm");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

@Test

void should_fail_when_execute_invalid_action_given_a_entrance_machine() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

assertThatThrownBy(() -> entranceMachine.execute(null))

.isInstanceOf(InvalidActionException.class);

}

@Test

void should_refund_when_insert_coin_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.INSERT_COIN);

then(result).isEqualTo("refund");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.UNLOCKED);

}

@Test

void should_closed_when_pass_given_a_entrance_machine_with_unlocked_state() {

EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.UNLOCKED);

String result = entranceMachine.execute(Action.PASS);

then(result).isEqualTo("closed");

then(entranceMachine.getState()).isEqualTo(EntranceMachineState.LOCKED);

}

}

EntraceMachine.java

package com.page.java.fsm;

import com.page.java.fsm.exception.InvalidActionException;

import lombok.Data;

import java.util.Objects;

@Data

public class EntranceMachine {

private EntranceMachineState state;

public EntranceMachine(EntranceMachineState state) {

setState(state);

}

public String execute(Action action) {

if (Objects.isNull(action)) {

throw new InvalidActionException();

}

return action.execute(this, state);

}

public String open() {

return "opened";

}

public String alarm() {

return "alarm";

}

public String refund() {

return "refund";

}

public String close() {

return "closed";

}

}

Action.java

package com.page.java.fsm;

public enum Action {

PASS {

@Override

public String execute(EntranceMachine entranceMachine, EntranceMachineState state) {

return state.pass(entranceMachine);

}

},

INSERT_COIN {

@Override

public String execute(EntranceMachine entranceMachine, EntranceMachineState state) {

return state.insertCoin(entranceMachine);

}

};

public abstract String execute(EntranceMachine entranceMachine, EntranceMachineState state);

}

EntranceMachineState.java

package com.page.java.fsm;

public enum EntranceMachineState {

LOCKED {

@Override

public String insertCoin(EntranceMachine entranceMachine) {

entranceMachine.setState(UNLOCKED);

return entranceMachine.open();

}

@Override

public String pass(EntranceMachine entranceMachine) {

entranceMachine.setState(this);

return entranceMachine.alarm();

}

},

UNLOCKED {

@Override

public String insertCoin(EntranceMachine entranceMachine) {

entranceMachine.setState(this);

return entranceMachine.refund();

}

@Override

public String pass(EntranceMachine entranceMachine) {

entranceMachine.setState(LOCKED);

return entranceMachine.close();

}

};

public abstract String insertCoin(EntranceMachine entranceMachine);

public abstract String pass(EntranceMachine entranceMachine);

}

InvalidActionException.java

package com.page.java.fsm.exception;

public class InvalidActionException extends RuntimeException {

}

通过上面的代码,可以发现Action、EntranceMachineState两个枚举的复杂度都提升了。不单单是定义了常量那么简单。还提供了相应的逻辑处理。

在EntranceMachineState.java的提交记录中,对进行了一次重构,将具体业务逻辑执行移动到EntranceMachine中,EntranceMachineState内每种状态的方法中只负责调度。这样能够通过EntranceMachineState相对直观的看清楚做了什么,状态变成了什么。

缺陷就是,EntranceMachine 对外提供了public的setState方法,这也就意味着调用者在将来维护是,很有可能滥用setState方法。

02 总结

通过上面4中对FSM的实现,我们看到每一种是实现都有优点和它的不足。那么在日常工作中,如何选择呢,我个人认为可以遵循一下两个建议:

遵循Simple Design。如果没有一个外部参考,那么用哪一种都不为过。所以引入一个原则作为参考,可以更好的帮助我们做决定。这里日常工作中我们经常使用Simple Design:通过测试、揭示意图、消除重复、最少元素。并在实现过程中不断重构,代码是重构出来的,而不是一次性的设计出来的。

在状态机的实现上多做尝试。例子只是一个简单的场景,所以只能看到简单场景下的实现效果,实际业务线上的状态会非常丰富,而且每种状态中可真行的动作也是不同的。所以针对特定场景遇到的问题,多尝试练习思考,练习思考后的经验才是最重要的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 有限状态机_有限状态机的4种Java实现对比 的相关文章

  • Java Session 会话技术

    一 Session简介 Session技术是将数据存储在服务器端的技术 会每个客户端都创建一块内存空间存储客户的数据 但客户端需要都携带一个标识ID去服务器中寻找属于自己的内存空间 所以说Session的实现是基于Cookie Sessio
  • 超参数优化--随机网格法

    随机网格搜索RandomizedSearchCV 在网格搜索时我们提到 伴随着数据和模型的复杂度提升 网格搜索所需要的时间急剧增加 以随机森林算法为例 如果使用过万的数据 搜索时间则会立刻上升好几个小时 因此 我们急需寻找到一种更加高效的超
  • vue 数组添加数据

    vue 数据添加分为三种方法 1 unshift 2 push 3 splice
  • vue点击导航 页面自动滚动到特定位置

    vue点击导航 页面自动滚动到特定位置 效果预览 1 npm i element ui S 下载安装element组件库 导航我们使用element组件库中的样式 type primary 刚好作为我们导航激活后的样式 省去了我们写样式的时
  • AVR 中 delay 函数的调用注意事项!delay_ns delay_ms

    早就知道AVR的编译器有自带的延时子函数 或者说是头文件 但一直没时间一探究竟 今天终于揭开了其内幕 AVR编译器众多 可谓是百家齐鸣 本人独尊WinAVR 说明 编译器版本WinAVR 20080610 先说winAVR的 Delay h
  • java 远程连接_java连接远程服务器(示例代码)

    我用的是smb协议 共享方式连接远程 Windows服务器 也可以用ftp 但要保证服务器是ftp的 连接Linux服务器可以用ssh 协议 新建一个res properites连接 IP 10 61 28 56 SMB MINGCHENG
  • 第7章 指针 第1题

    题目 用原型 void getDate int dd int mm int yy 写一个函数 从键盘读入一个形如dd mmm yy的日期 其中dd是一个1位或2位的表示日的整数 mmm是月份的3个字母的缩写 yy是两位数的年份 函数读入这个
  • teamviewer连接不上的原因及解决方法有哪些

    teamviewer连接不上的原因及解决方法有哪些 一 总结 一句话总结 这里说的就是版本问题 高版本可以连接低版本 低版本无法连接高版本 1 TeamViewer官方检测使用环境是否为商用的标准是什么 1 自安装软件以来 累计连接的电脑多
  • 这个人就是吴恩达(Andrew Ng),百度新任首席科学家

    这个人就是吴恩达 Andrew Ng 百度新任首席科学家 虎嗅 2013 05 11 10 32 收藏43 评论35 虎嗅注 人工智能现在是科技界最前沿的话题之一 以谷歌为代表 科技巨头均在这个方向上进行巨大投入 虎嗅曾发表过一篇文章 谷歌
  • 【神兵利器】介绍一款基于GPT-4完全免费的编程软件:Cursor!

    Cursor 一款基于GPT 4完全免费的编程软件 PS 文章首发于公众号 字节卷动 官网地址 官网 https www cursor so IDE作者 https twitter com amanrsanger 这是我找到的第一个免费的
  • python比较两个csv文件,并打印出不同的行号,列号,数据

    https blog csdn net The Handsome Sir article details 121251433 def compareFile file1 file2 如果相等返回 1 0 0 如果不相等返回 0 a b a
  • 【满分】【华为OD机试真题2023 JS】AI处理器组合

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 AI处理器组合 知识点数组 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 某公司研发了一款高性能AI处理器 每台物理设备具备8颗AI处理器 编号分别为0 1 2
  • Y形电路与三角电路转换,网孔和节点分析法

    Y形电路与三角电路转换 网孔和节点分析法 Y形电路与三角电路转换 推导过程与之前的电压源和电流源的转换类似 用系数相等即可等价转换 此处直接给出结论与记法 网孔分析法 自电阻 在这个网孔中所有电阻的和 互电阻 网孔1与网孔2之间的电阻 将每
  • 机器学习——决策树算法

    一 实验目的 掌握如何实现决策树算法 用并决策树算法完成预测 二 实验内容 本次实验任务我们使用贷款申请样本数据表 该数据表中每列数据分别代表ID 年龄 高薪 有房 信贷情况 类别 我们根据如下数据生成决策树 使用代码来实现该决策树算法 三
  • Linux->线程库接口

    目录 前言 1 进程和线程 2 线程库接口 2 1 线程库基础理解 2 2 创建线程 2 2 线程资源回收 2 3 线程分离 前言 本篇主要是对Linux原装线程库的函数接口进行学习 还有一部分的线程概念补充 1 进程和线程 博主在上一篇文
  • android--emo的来源

    文章目录 前言 第一次安装 bug出现了 idea配置android开发环境 碰运气 重新下载 导入项目 测试成功 感悟 前言 记录一下我安装android studio的心路历程 为什么就我遇到这么多问题 第一次安装 这学期新开的移动应用
  • python选择与循环结构之判断三角形:任意输入三个整数作为三角形边长,判断三条边能否构成三角形,并判断是等边三角形、等腰三角形,直角三角形,还是一般三角形。

    问题描述 任意输入三个整数作为三角形边长 判断三条边能否构成三角形 并判断是等边三角形 等腰三角形 直角三角形 还是一般三角形 实现代码如下 a int input 请输入a b int input 请输入b c int input 请输入
  • Winsock Error Codes

    Winsock Error Codes 10004 WSAEINTRInterrupted function call This error indicates that a blocking call was interrupted by
  • JavaScript 严格模式(use strict)

    JavaScript严格模式 又称为 use strict 模式 是JavaScript语言的一种更严格的运行模式 严格模式规定了一些限制 用于防止程序员犯一些常见的错误 以保证代码的正确性和安全性 在JavaScript严格模式中 不允许

随机推荐

  • 刷脸支付智慧经营创业红利赢在坚持不懈

    这是一个最好的时代 我们身处繁华的都市 有着一个体面稳定的工作 科技日新月异 生活便捷高效 这是一个最坏的时代 房价水涨船高 工资涨幅完全跟不上物价的涨幅 8090后年轻人们面临着巨大的生活压力 钱 成为了禁锢他们的牢笼 在这个时代 普通人
  • Mybatis如何处理Result Maps collection already contains value for xxx异常呢?

    转自 Mybatis如何处理Result Maps collection already contains value for xxx异常呢 下文笔者讲述一次mybatis异常的处理分享 如下所示 Mybatis异常摘要 2022 08 1
  • Java初识RabbitMQ一交换机(fanout exchange)

    扇型交换机 funout exchange 将消息路由给绑定到它身上的所有队列 而不理会绑定的路由键 如果 N 个队列绑定到某个扇型交换机上 当有消息发送给此扇型交换机时 交换机会将消息的拷贝分别发送给这所有的 N 个队列 因为扇型交换机投
  • 取消已设置为SVN的文件夹(清理SVN标志)

    取消CheckOut后的文件与svn的联系 Windows Registry Editor Version 5 00 HKEY LOCAL MACHINE SOFTWARE Classes Folder shell DeleteSVN 删除
  • 代码随想录训练营第14天

    参考 代码随想录 一 理论基础 一 二叉树的种类 满二叉树 完全二叉树 二叉搜索树 平衡二叉搜索树 二 二叉树的存储方式 顺序存储 顺序存储的元素在内存中是连续分布的 通常用数组来存储 如果父节点的数组下标是 i 那么它的左孩子就是 i 2
  • ucos学习资料、论坛等

    论坛 http bbs elecfans com forum php mod forumdisplay fid 301 typeid 505 教程推荐 第一步 嵌入式实时操作系统 COS II原理及应用 任哲编著 首选任哲的这本书 我建议先
  • 对IOC和DI的通俗理解

    学习过spring框架的人一定都会听过Spring的IoC 控制反转 DI 依赖注入 这两个概念 对于初学Spring的人来说 总觉得IoC DI这两个概念是模糊不清的 是很难理解的 今天和大家分享网上的一些技术大牛们对Spring框架的I
  • Flink ML API,为实时机器学习设计的算法接口与迭代引擎

    摘要 本文整理自阿里巴巴高级技术专家林东 阿里巴巴技术专家高赟 云骞 在 Flink Forward Asia 2021 核心技术专场的演讲 主要内容包括 面向实时机器学习的 API 流批一体的迭代引擎 Flink ML 生态建设 一 面向
  • Linux下快速查看CPU使用情况的相关命令

    Linux下快速查看CPU使用情况比较常用的命令是free top ps 这篇文章来看下如何在Linux下检查服务器的CPU使用情况 我的Linux是Linux Ubuntu server 15 04 如果是图形界面 有些统计会看起来更直观
  • Intellij Idea创建一个简单的java项目

    2016年11月12日 我即将要离开象牙塔 校园 踏入社会 想想未来我是某个公司的一个程序员 再对比一下小时的梦想 好像出入挺大的 今天我不得不为即将的工作准备 一个java开发工程师 但是我现在是一个小小的菜鸟 所以要学习 好了 不说这些
  • 简单说说对QT中moveToThread实现多线程操作的理解

    在平时的编码过程中经常碰到QT的多线程问题 也大量接触了QT中的两种主流多线程写法 一种是继承QThread类并重载run函数 在run函数中写一个状态机或者计时器来实现对线程运作 一种是通过moveToThread的方式实现事件托管从而实
  • nginx在Linux上搭建

    一 Nginx介绍和常用功能 1 Nginx介绍 Nginx是一个高性能的HTTP和反向代理 服务器 百度百科的介绍 常见功能 Http代理 反向代理 作为web服务器最常用的功能之一 尤其是反向代理 正向代理和反向代理不理解的可以看htt
  • 轮播图插件使用

    React使用最广泛的轮播图插件之一是 react slick react slick 是一个基于React的响应式轮播图组件 具有许多可定制的选项和功能 要使用 react slick 插件 您可以按照以下步骤进行 1 安装 react
  • 华为数据中心产品汇总介绍

    AR G3路由器产品定位 AR G3系列企业路由器是秉承华为在数据通信 无线 接入网 核心网领域的深厚积累 依托自主知识产权的VRP平台 通用路由平台 主要是以TCP IP协议为核心 实现了数据链路层 网络层和应用层的多种协议 推出的面向企
  • yagmail发送带图片和链接的邮件

    方法 在正文中插入图片 yagmail inlne 图片路径 在正文中插入链接 a href 链接地址 链接名称 a 效果如图 经过测试的完整代码 导入yagmail第三方库 import yagmail yagmail SMTP user
  • 冻结表格列PyQt

    QT有个官方的例子 Frozen Column Example 在Qt Creator例子查找即可 官方例子python版本 Frozen Column Example Qt for Python 不过官方python版应该是机器直接翻译的
  • C++ continue 语句

    C 中的 continue 语句有点像 break 语句 但它不是强迫终止 continue 会跳过当前循环中的代码 强迫开始下一次循环 对于 for 循环 continue 语句会导致执行条件测试和循环增量部分 对于 while 和 do
  • 十进制转换为二进制代码

    十进制转换为二进制代码 十进制转换为二进制 十进制如何转二进制 将该数字不断除以2直到商为零 然后将余数由下至上依次写出 即可得到该数字的二进制表示 以将数字21转化为二进制为例 当商为零时 将余数由下至上依次写出 即为21的二进制表示 i
  • SpringBoot整合框架——数据库

    目录 一 整合JDBC使用 1 1 SpringData简介 1 2 创建测试项目测试数据源 1 3 JDBCTemplate JdbcTemplate主要提供以下几类方法 1 4 测试 二 整合Druid
  • java 有限状态机_有限状态机的4种Java实现对比

    写在前面 2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上 内容详细 图文并茂 有需要学习的朋友可以Star一下 GitHub地址 https github com abel max Java Study Not