如何写出优雅的代码

概述

优雅的代码就是那种看起来简单、易懂,而且好维护的代码。它的设计让人一眼就能明白每部分的作用,避免了复杂和冗余的部分。它使用清晰的变量和方法名称,能让你很快理解代码在做什么,而不是去猜测。

优雅的代码还遵循一些编程的好习惯,比如把代码分成小块,每块负责一个特定的功能,这样更容易修改和扩展。

优雅处理if-else

在实际开发中,要想代码变的更优雅,对if-else的处理是绝对绕不过去的。举个例子,当你需要处理多种不同类型的请求时,直接在一个方法中使用一大堆if-else语句来区分不同的逻辑会使代码显得臃肿且难以维护。

public class PaymentService {
    public void processPayment(String type) {
        if (type.equals("creditcard")) {
            // 处理信用卡支付
            System.out.println("Processing credit card payment.");
        } else if (type.equals("paypal")) {
            // 处理 PayPal 支付
            System.out.println("Processing PayPal payment.");
        } else if (type.equals("bitcoin")) {
            // 处理比特币支付
            System.out.println("Processing Bitcoin payment.");
        } else if (type.equals("banktransfer")) {
            // 处理银行转账支付
            System.out.println("Processing Bank Transfer payment.");
        } else {
            throw new IllegalArgumentException("Unsupported payment type");
        }
    }
}

替换if-else并不会降低代码的复杂度,相反比较少见的写法可能会增加认知负荷,从而进一步增加了复杂度。之所以要替换过多的if-else是为了对代码进行解耦合,方便扩展代码,最终方便对代码的维护。

以下有几种常见的方法来处理if-else

尽早结束if

避免深层嵌套的if-else结构,通过在方法的开头处理特殊情况或边界条件,然后直接返回,可以让主要逻辑保持平坦,便于阅读和理解。

public void processOrder(Order order) {
    if (order == null) {
        throw new IllegalArgumentException("Order cannot be null");
    }

    if (order.isCancelled()) {
        // 处理已取消的订单
        return;
    }

    if (order.isShipped()) {
        // 处理已发货的订单
        return;
    }

    // 处理未处理的订单
}

使用switch-case

使用switch-case语句可以帮助简化多个if-else语句,使代码更清晰和易读。为了使代码更加优雅和易于维护,可以利用枚举类型来提高代码的安全性,避免重复代码,并在default分支中处理异常情况。

public enum Command {
    START, STOP, PAUSE;
}

public void handleCommand(Command command) {
    switch (command) {
        case START:
            start();
            break;
        case STOP:
            stop();
            break;
        case PAUSE:
            pause();
            break;
        default:
            throw new IllegalArgumentException("Unknown command: " + command);
    }
}

private void start() {
    System.out.println("Starting...");
}

private void stop() {
    System.out.println("Stopping...");
}

private void pause() {
    System.out.println("Pausing...");
}

使用枚举替代if-else

如果if-else语句是基于对象类型或状态的,考虑使用多态。将不同的行为封装到不同的类中,可以避免大量的条件判断。这种方法在许多设计模式中得到了应用,如策略模式、命令模式和状态模式等。

使用枚举代替if-else的方式也是多态的一种应用,这种方法通过将不同的行为封装在枚举常量中,实现了多态的效果,从而简化了条件判断逻辑。

public class MyTest {
    public static void main(String[] args) {
        String val = "FOUR";
        condition(val);
        System.out.println("--------------");
        newCondition(val);
    }

    public static void condition(String val) {
        if ("ONE".equals(val)) {
            System.out.println("val:" + 1111111);
        } else if ("TWO".equals(val)) {
            System.out.println("val:" + 2222222);
        } else if ("THREE".equals(val)) {
            System.out.println("val:" + 3333333);
        } else {
            System.out.println("val:" + val);
        }
    }

    public static void newCondition(String val) {
        ConditionEnum conditionEnum;
        try {
            conditionEnum = ConditionEnum.valueOf(val);
        } catch (IllegalArgumentException e) {
            System.out.println("val:" + val);
            return;
        }
        exec(conditionEnum);
    }

    public static void exec(ConditionEnum conditionEnum) {
        conditionEnum.context();
    }

    enum ConditionEnum {
        ONE {
            @Override
            public void context() {
                System.out.println("val:" + 1111111);
            }
        },
        TWO {
            @Override
            public void context() {
                System.out.println("val:" + 2222222);
            }
        },
        THREE {
            @Override
            public void context() {
                System.out.println("val:" + 3333333);
            }
        };

        public abstract void context();
    }

}

也可用枚举替换成这样:

public static void newCondition(String val) {
    ConditionEnum condition = ConditionEnum.getCondition(val);
    System.out.println("val:" + (condition == null ? val : condition.value));
}

enum ConditionEnum {
    ONE("ONE",1111111),
    TWO("TWO",2222222),
    THREE("THREE",3333333)

    ;

    private String key;
    private Integer value;

    ConditionEnum(String key,Integer value){
        this.key = key;
        this.value = value;
    }

    public  static ConditionEnum getCondition(String key){
        return Arrays.stream(ConditionEnum.values()).filter(x -> Objects.equals(x.key, key)).findFirst().orElse(null);
    }
}

使用Map替代if-else

当条件逻辑是基于键值对时,可以使用Map可以替代多个if-else语句,简化代码结构。

public class MyTest {
    public static void main(String[] args) {
        String val = "1";
        condition(val);
        System.out.println("--------------");
        newCondition(val);
    }
    public static void condition(String val) {
        if ("1".equals(val)){
            System.out.println("val:" + 1111111);
        }else if ("2".equals(val)){
            System.out.println("val:" + 2222222);
        }else if ("3".equals(val)){
            System.out.println("val:" + 3333333);
        }else {
            System.out.println("val:" + val);
        }
    }
    public static void newCondition(String val){
        Map<String, Function<?,?>> map = new HashMap<>();
        map.put("1",(action) -> 1111111);
        map.put("2",(action) -> 2222222);
        map.put("3",(action) -> 3333333);
        System.out.println("val:" + (map.get(val) != null ? map.get(val).apply(null) : val));
    }
}

使用职责链模式替代if-else

职责链模式是一种行为型设计模式,它允许将请求沿着处理对象的链传递,直到一个对象处理它。这个模式避免了使用大量的if-elseswitch-case语句,尤其适合用于处理多个条件和动态的请求处理流程。

// 处理者接口
public abstract class Approver {
    protected Approver nextApprover;

    public void setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
    }

    public abstract void handleRequest(int amount);
}

// 具体处理者:经理
public class Manager extends Approver {
    @Override
    public void handleRequest(int amount) {
        if (amount <= 1000) {
            System.out.println("Manager approved $" + amount);
        } else if (nextApprover != null) {
            nextApprover.handleRequest(amount);
        }
    }
}

// 具体处理者:总监
public class Director extends Approver {
    @Override
    public void handleRequest(int amount) {
        if (amount <= 5000) {
            System.out.println("Director approved $" + amount);
        } else if (nextApprover != null) {
            nextApprover.handleRequest(amount);
        }
    }
}

// 具体处理者:副总裁
public class VicePresident extends Approver {
    @Override
    public void handleRequest(int amount) {
        if (amount <= 10000) {
            System.out.println("Vice President approved $" + amount);
        } else {
            System.out.println("Request amount is too large.");
        }
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        // 创建处理者链
        Approver manager = new Manager();
        Approver director = new Director();
        Approver vp = new VicePresident();

        manager.setNextApprover(director);
        director.setNextApprover(vp);

        // 发起请求
        int[] amounts = {500, 1500, 6000, 15000};

        for (int amount : amounts) {
            System.out.println("Requesting $" + amount);
            manager.handleRequest(amount);
            System.out.println();
        }
    }
}

使用模板方法模式替代if-else

模板方法模式是一种行为型设计模式,它允许在父类中定义一个算法的骨架,并将一些步骤的实现推迟到子类中。这种模式可以通过定义一个模板方法,将固定的算法步骤与可变的步骤分开,从而减少if-else语句的使用,简化代码结构。

// 抽象类
public abstract class DocumentProcessor {
    // 模板方法
    public final void processDocument() {
        readDocument();
        processContent();
        saveDocument();
    }

    // 固定步骤:读取文档
    private void readDocument() {
        System.out.println("Reading document...");
    }

    // 固定步骤:保存文档
    private void saveDocument() {
        System.out.println("Saving document...");
    }

    // 可变步骤:处理文档内容,子类实现
    protected abstract void processContent();
}

// 具体类:处理PDF文档
public class PDFDocumentProcessor extends DocumentProcessor {
    @Override
    protected void processContent() {
        System.out.println("Processing PDF content...");
    }
}

// 具体类:处理Word文档
public class WordDocumentProcessor extends DocumentProcessor {
    @Override
    protected void processContent() {
        System.out.println("Processing Word content...");
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        DocumentProcessor pdfProcessor = new PDFDocumentProcessor();
        DocumentProcessor wordProcessor = new WordDocumentProcessor();

        System.out.println("Processing PDF Document:");
        pdfProcessor.processDocument();
        System.out.println();

        System.out.println("Processing Word Document:");
        wordProcessor.processDocument();
    }
}

使用工厂方法模式替代if-else

工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定实例化哪一个类。工厂方法模式通过将对象的创建推迟到子类中,避免了在代码中出现大量的if-elseswitch-case语句,从而简化了代码结构。

// 产品接口
public interface DatabaseConnection {
    void connect();
}

// 具体产品:MySQL数据库连接
public class MySQLConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connecting to MySQL database...");
    }
}

// 具体产品:Oracle数据库连接
public class OracleConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connecting to Oracle database...");
    }
}

// 创建者接口
public abstract class DatabaseFactory {
    public abstract DatabaseConnection createConnection();
}

// 具体创建者:MySQL工厂
public class MySQLFactory extends DatabaseFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new MySQLConnection();
    }
}

// 具体创建者:Oracle工厂
public class OracleFactory extends DatabaseFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new OracleConnection();
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        // 根据需求选择具体的工厂
        DatabaseFactory factory = getDatabaseFactory("MySQL");
        DatabaseConnection connection = factory.createConnection();
        connection.connect();
    }

    private static DatabaseFactory getDatabaseFactory(String dbType) {
        if (dbType.equalsIgnoreCase("MySQL")) {
            return new MySQLFactory();
        } else if (dbType.equalsIgnoreCase("Oracle")) {
            return new OracleFactory();
        } else {
            throw new IllegalArgumentException("Unknown database type");
        }
    }
}

使用策略模式替代if-else

策略模式是一种行为型设计模式,它定义了一系列的算法,将每一个算法封装起来,并使它们可以相互替换。策略模式使得算法可以独立于使用它的客户端而变化,从而减少了if-elseswitch-case语句的使用,提供了更灵活的代码结构。

// 策略接口
public interface TextFormatter {
    String format(String text);
}

// 具体策略:大写格式化
public class UpperCaseFormatter implements TextFormatter {
    @Override
    public String format(String text) {
        return text.toUpperCase();
    }
}

// 具体策略:小写格式化
public class LowerCaseFormatter implements TextFormatter {
    @Override
    public String format(String text) {
        return text.toLowerCase();
    }
}

// 上下文
public class TextEditor {
    private TextFormatter formatter;

    public void setFormatter(TextFormatter formatter) {
        this.formatter = formatter;
    }

    public void printFormattedText(String text) {
        if (formatter != null) {
            String formattedText = formatter.format(text);
            System.out.println(formattedText);
        } else {
            System.out.println("No formatter set.");
        }
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();

        // 使用大写格式化策略
        editor.setFormatter(new UpperCaseFormatter());
        editor.printFormattedText("Hello, World!");

        // 使用小写格式化策略
        editor.setFormatter(new LowerCaseFormatter());
        editor.printFormattedText("Hello, World!");
    }
}

使用注解替代if-else

使用注解替代if-else语句是一种现代化的编程方式,可以简化代码并减少条件判断的复杂性。注解可以用来描述程序的各种元数据,这些元数据可以在运行时或编译时被处理,从而决定某些行为。通过注解和相关的处理器,可以将决策逻辑从代码中抽离出来,减少if-else语句的使用。

@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.TYPE)  
public @interface PayCode {  

     String value();    
     String name();  
}
@PayCode(value = "alia", name = "支付宝支付")  
@Service
public class AliaPay implements IPay {  

     @Override
     public void pay() {  
         System.out.println("===发起支付宝支付===");  
     }  
}  


@PayCode(value = "weixin", name = "微信支付")  
@Service
public class WeixinPay implements IPay {  

     @Override
     public void pay() {  
         System.out.println("===发起微信支付===");  
     }  
} 


@PayCode(value = "jingdong", name = "京东支付")  
@Service
public class JingDongPay implements IPay {  

     @Override
     public void pay() {  
        System.out.println("===发起京东支付===");  
     }  
}
@Service
public class PayService2 implements ApplicationListener<ContextRefreshedEvent> {  

     private static Map<String, IPay> payMap = null;  

     @Override
     public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {  
         ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();  
         Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);  

         if (beansWithAnnotation != null) {  
             payMap = new HashMap<>();  
             beansWithAnnotation.forEach((key, value) ->{  
                 String bizType = value.getClass().getAnnotation(PayCode.class).value();  
                 payMap.put(bizType, (IPay) value);  
             });  
         }  
     }  

     public void pay(String code) {  
        payMap.get(code).pay();  
     }  
}

优雅判空

在开发中,处理空值是一个常见而且重要的任务。不当的处理不仅会导致代码变得复杂和难以维护,还可能引发运行时错误。特别是当我们的代码中充斥着大量的null检查和条件判断时,程序的可读性和可维护性会大打折扣。优雅地处理空值,不仅是为了提高代码的健壮性,更是为了提升代码的可读性和设计质量。

使用工具类判空

使用工具类来处理空值是一种常见的做法,工具类可以集中处理空值检查逻辑,使代码更加简洁和一致。常见工具类有,Spring中的Assert类、JDK中的Objects类、Apache Commons Lang库的StringUtils类。

Apache Commons Lang库的StringUtils提供了许多用于处理字符串和空值的方法。

public class Example {
    public void printLength(String str) {
        // 使用 StringUtils.defaultIfEmpty 提供默认值
        String nonNullStr = StringUtils.defaultIfEmpty(str, "Default Value");
        System.out.println("Length of string: " + nonNullStr.length());
    }
}

Objects类是 Java7引入的,它提供了一些静态方法来简化对null的检查。

public class Example {
    public void printLength(String str) {
        // 使用 Objects.requireNonNullElse 提供默认值
        String nonNullStr = Objects.requireNonNullElse(str, "Default Value");
        System.out.println("Length of string: " + nonNullStr.length());
    }
}

在Spring框架中,Assert类是一个工具类,提供了一组静态方法用于验证条件。它可以帮助开发者在代码中做各种检查,如非空检查、范围检查等,若条件不满足则抛出相应的异常。

public class MyTest {
    public static void main(String[] args) {
        Object obj = new Object();
        Assert.notNull(obj,"对象不能为空");
        Assert.isTrue(obj != null,"对象不能为空");
        ArrayList<Object> list = new ArrayList<>();
        Assert.notEmpty(list,"list不能为空");
    }
}

使用Optional判空

Optional是Java8引入的一个容器类,用于表示可能为空的值。它提供了多种方法来处理空值情况,避免了显式的null检查。

public class UserService {

    public Optional<User> findUserById(String userId) {
        // 模拟查询用户,返回可能为空的结果
        User user = database.findUserById(userId);
        return Optional.ofNullable(user);
    }

    public void processUser(String userId) {
        Optional<User> userOpt = findUserById(userId);
        userOpt.ifPresent(user -> {
            // 处理用户
            System.out.println("User found: " + user.getName());
        });
    }
}

自定义链式调用,对Optional扩展。

/**
* @author Axin
* @since 2020-09-10
* @summary 链式调用 bean 中 value 的方法
*/
public final class OptionalBean<T> {

    private static final OptionalBean<?> EMPTY = new OptionalBean<>();

    private final T value;

    private OptionalBean() {
        this.value = null;
    }

    /**
     * 空值会抛出空指针
     * @param value
     */
    private OptionalBean(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 包装一个不能为空的 bean
     * @param value
     * @param <T>
     * @return
     */
    public static <T> OptionalBean<T> of(T value) {
        return new OptionalBean<>(value);
    }

    /**
     * 包装一个可能为空的 bean
     * @param value
     * @param <T>
     * @return
     */
    public static <T> OptionalBean<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 取出具体的值
     * @param fn
     * @param <R>
     * @return
     */
    public T get() {
        return Objects.isNull(value) ? null : value;
    }

    /**
     * 取出一个可能为空的对象
     * @param fn
     * @param <R>
     * @return
     */
    public <R> OptionalBean<R> getBean(Function<? super T, ? extends R> fn) {
        return Objects.isNull(value) ? OptionalBean.empty() : OptionalBean.ofNullable(fn.apply(value));
    }

    /**
     * 如果目标值为空 获取一个默认值
     * @param other
     * @return
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * 如果目标值为空 通过lambda表达式获取一个值
     * @param other
     * @return
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 如果目标值为空 抛出一个异常
     * @param exceptionSupplier
     * @param <X>
     * @return
     * @throws X
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    public boolean isPresent() {
        return value != null;
    }

    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    /**
     * 空值常量
     * @param <T>
     * @return
     */
    public static<T> OptionalBean<T> empty() {
        @SuppressWarnings("unchecked")
        OptionalBean<T> none = (OptionalBean<T>) EMPTY;
        return none;
    }

}
@Data
public class User {

    private String name;

    private String gender;

    private School school;

    @Data
    public static class School {

        private String scName;

        private String adress;
    }
}
public static void main(String[] args) {

    User axin = new User();
    User.School school = new User.School();
    axin.setName("hello");

    // 1. 基本调用
    String value1 = OptionalBean.ofNullable(axin)
            .getBean(User::getSchool)
            .getBean(User.School::getAdress).get();
    System.out.println(value1);

    // 2. 扩展的 isPresent方法 用法与 Optional 一样
    boolean present = OptionalBean.ofNullable(axin)
            .getBean(User::getSchool)
            .getBean(User.School::getAdress).isPresent();
    System.out.println(present);


    // 3. 扩展的 ifPresent 方法
    OptionalBean.ofNullable(axin)
            .getBean(User::getSchool)
            .getBean(User.School::getAdress)
            .ifPresent(adress -> System.out.println(String.format("地址存在:%s", adress)));

    // 4. 扩展的 orElse
    String value2 = OptionalBean.ofNullable(axin)
            .getBean(User::getSchool)
            .getBean(User.School::getAdress).orElse("家里蹲");

    System.out.println(value2);

    // 5. 扩展的 orElseThrow
    try {
        String value3 = OptionalBean.ofNullable(axin)
                .getBean(User::getSchool)
                .getBean(User.School::getAdress).orElseThrow(() -> new RuntimeException("空指针了"));
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

使用Validator注解判空

在Java中,使用Validator注解进行判空是一种优雅的方式来验证对象的状态,特别是在处理用户输入和表单数据时。javax.validation包中的注解可以帮助确保对象的属性满足指定的条件,如非空、长度限制等。这些注解通常与 Java Bean Validation规范一起使用,并可以通过Spring的@Valid注解在控制器中自动触发验证。

从SpringBoot2.3开始,校验包被独立成了一个starter组件,所以需要引入validationweb,而springboot-2.3之前的版本只需要引入web依赖就可以了。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
/**
 * 常用校验注解
 * JSR提供的校验注解:
 * @Null 被注释的元素必须为 null
 * @NotNull 被注释的元素必须不为 null
 * @AssertTrue 被注释的元素必须为 true
 * @AssertFalse 被注释的元素必须为 false
 * @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
 * @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
 * @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
 * @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
 * @Size(max=, min=)   被注释的元素的大小必须在指定的范围内
 * @Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内
 * @Past 被注释的元素必须是一个过去的日期
 * @Future 被注释的元素必须是一个将来的日期
 * @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
 *
 */
@Data
public class UserEntity1 {

    @NotNull(message = "id不能为空")
    private Integer id;

    @NotBlank(message = "用户名不能为空")
    private String username;

    @Size(max = 10,min = 7,message = "密码位数必须在7-10位")
    @NotBlank(message = "密码不能为空")
    private String password;

    @NotBlank(message = "企业名称不能为空")
    private String enterpriseName;

    @Null
    private Integer contactId;

    @Null
    private BigDecimal money;

    @Email(message = "电子邮箱不能为空")
    private String email;

    @NotBlank(message = "手机号不能为空")
    private String mobile;

}
@Controller
@RequestMapping("/user")
public class UserController {

    @PostMapping("/create")
    @ResponseBody
    public String createUser(@Valid @RequestBody User user) {
        // 如果 user 对象不符合验证规则,Spring 会自动返回错误响应
        return "User created successfully";
    }
}
  • 46
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_whitepure

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值