Лучшие практики функционального программирования Java

функциональное программирование

Я не хочу вдаваться в подробности о гнилом потоковом API, я хочу поделиться с вами тем, как использовать функциональное программирование для упрощения нашей разработки, я хочу сказать другое.

Упрощение транзакций

Для транзакций степень детализации должна быть как можно меньше, а логика чтения и записи должны быть разделены и выполнять транзакции только в логике записи.Функциональное программирование можно использовать для упрощения этапа извлечения логики записи.

@Service
public class TransactionService {
    @Transactional
    public void process(ThrowExceptionRunnable runnable){
        try {
            runnable.run();
        }catch (Exception e){
            new RuntimeException(e);
        }
    }
}

//使用方式
public void regist(String username){
	User user = userService.findByUserName(username);
  	if(user != null) return;
  	
  	//执行事务 注册用户 开通余额账号
  	transactionService.process(() -> {
      	userService.save(new User(username));
        balanceService.save(new Balance(username));
    });
}

Дайте методу возможность повторить попытку

    public static void retryFunction(ThrowExceptionRunnable runnable, int time) {
        while (true) {
            try {
                runnable.run();
                return;
            } catch (Exception e) {
                time--;
                if (time <= 0) throw new RuntimeException(e);
            }
        }
    }
    public static <T, R> R retryFunction(ThrowExceptionFunction<T, R> function, T t, int time) {
        while (true) {
            try {
                return function.apply(t);
            } catch (Exception e) {
                time--;
                if (time <= 0) throw new RuntimeException(e);
            }
        }
    }
    public static <T, U, R> R retryFunction(ThrowExceptionBiFunction<T, U, R> function, T t, U u, int time) {
        while (true) {
            try {
                return function.apply(t, u);
            } catch (Exception e) {
                time--;
                if (time <= 0) throw new RuntimeException(e);
            }
        }
    }
    public static void main(String[] args) {
  	//http调用,失败会重试3次
     	retryFunction(()->http.call(),3);
  	//把数字1转成数字 失败会重试三次
  	String s = retryFunction(String::valueOf, 1, 3);
  	String ss = retryFunction(i -> String.valueOf(i), 1, 3);
    }

Дайте возможность кэширования функций

public static <T, R> R cacheFunction(Function<T, R> function, T t, Map<T, R> cache) {
    R r = cache.get(t);
    if (r != null) return r;
    R result = function.apply(t);
    cache.put(t,result);
    return result;
}

public static void main(String[] args) {
        Map<String,User> cache = new HashMap<Integer, User>();
        String username = "张三";
  			//不走缓存
        cacheFunction(u -> userService.findByUserName(u),username,cache);
  			//走缓存
        cacheFunction(u -> userService.findByUserName(u),username,cache);
    }

Дайте функции возможность сообщать об ошибке и возвращать значение по умолчанию.

    public static <T, R> R computeOrGetDefault(ThrowExceptionFunction<T, R> function, T t, R r) {
        try {
            return function.apply(t);
        } catch (Exception e) {
            return r;
        }
    }
    public static <R> R computeOrGetDefault(ThrowExceptionSupplier<R> supplier,R r){
        try {
            return supplier.get();
        } catch (Exception e) {
            return r;
        }
    }

	public static void main(String[] args) {
  	//返回0
  	computeOrGetDefault(i -> {
           if (i < 0) throw new RuntimeException();
           else return i;
        }, -1, 0);
  	//返回5
        computeOrGetDefault(i -> {
            if (i < 0) throw new RuntimeException();
            else return i;
        },5,0);
    }

Дайте функциям возможность обрабатывать исключения

    public static <T, R> R computeAndDealException(ThrowExceptionFunction<T, R> function, T t, Function<Exception, R> dealFunc) {
        try {
            return function.apply(t);
        } catch (Exception e) {
            return dealFunc.apply(e);
        }
    }

    public static <T, U, R> R computeAndDealException(ThrowExceptionBiFunction<T,U, R> function, T t, U u,Function<Exception, R> dealFunc) {
        try {
            return function.apply(t,u);
        } catch (Exception e) {
            return dealFunc.apply(e);
        }
    }

    public static <R> R computeAndDealException(ThrowExceptionSupplier<R> supplier, Function<Exception, R> dealFunc) {
        try {
            return supplier.get();
        } catch (Exception e) {
            return dealFunc.apply(e);
        }
    }

public static void main(String[] args) {
    //返回异常message的hashcode
    Integer integer = computeAndDealException(i -> {
        if (i < 0) throw new RuntimeException("不能小于0");
        else return i;
    }, -1, e -> e.getMessage().hashCode());
    System.out.println(integer);
  
}

Дает функции возможность регистрировать

public static <T, R> R logFunction(Function<T, R> function, T t, String logTitle) {
    long startTime = System.currentTimeMillis();
    log.info("[[title={}]],request={},requestTime={}", logTitle, t.toString(),
    	    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    R apply = function.apply(t);
    long endTime = System.currentTimeMillis();
    log.info("[[title={}]],response={},spendTime={}ms", logTitle, apply.toString(), endTime - startTime);
    return apply;
}

public static void main(String[] args) {
    logFunction(String::valueOf,"s","String.valueOf");
}

пользовательский интерфейс функций

    @FunctionalInterface
    public interface ThrowExceptionFunction<T, R> {
        R apply(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowExceptionBiFunction<T, U, R> {
        R apply(T t, U u) throws Exception;
    }
    @FunctionalInterface
    public interface ThrowExceptionSupplier<T> {
        T get() throws Exception;
    }
    @FunctionalInterface
    public interface ThrowExceptionRunnable {
        void run() throws Exception;
    }

Q: Почему вы хотите настроить интерфейс функции

О: Интерфейс встроенной функции не может обрабатывать проверенные исключения, и при обнаружении метода с проверенными исключениями будет сообщено об ошибке.

Какие сценарии я использовал?

связанный доступ

При переводе php кода мы часто сталкиваемся со следующими ситуациями

$s = a.b.c.d.e.f.g

Затем при переводе в java-код выглядит так

String s = a.getB().getC().getD().getE().getF().getG();

В чем проблема? Пустого суждения не бывает. Пока есть пустой слой посередине, то это NPE. Если вы напишете логику пустого суждения, это будет фатально.

В это время мы можем использовать вышеупомянутую операцию Sao.

переписывание кода

String s = computeOrGetDefault(()->a.getB().getC().getD().getE().getF().getG(),"");
дела
Простая операция перехода на более раннюю версию (computeAndDealException)
повторная попытка интерфейса
кеш интерфейса
журнал