<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hùng Trần</title>
    <description>The latest articles on DEV Community by Hùng Trần (@hungtvk12).</description>
    <link>https://dev.to/hungtvk12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1835835%2F2ccbceda-a3be-4eb0-9d38-b86b8d5ef4eb.jpg</url>
      <title>DEV Community: Hùng Trần</title>
      <link>https://dev.to/hungtvk12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hungtvk12"/>
    <language>en</language>
    <item>
      <title>Rest API: How to Prevent Duplicate Requests Effectively</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Tue, 01 Oct 2024 14:49:13 +0000</pubDate>
      <link>https://dev.to/hungtvk12/rest-api-how-to-prevent-duplicate-requests-effectively-2egn</link>
      <guid>https://dev.to/hungtvk12/rest-api-how-to-prevent-duplicate-requests-effectively-2egn</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33jw5cxt2jedn07njxpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33jw5cxt2jedn07njxpf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solution to prevent duplicate requests that I want to talk about here is that when a user manipulates an API feed or any data source, in reality, they only manipulate once, but for any reason, such as intentionally by the user or maybe by a hacker, to cause system data errors.&lt;/p&gt;

&lt;p&gt;To prevent this from happening, we need to build a deduplication solution. In the scope of this article, I will implement deduplication based on Redis and Spring Boot 3.&lt;/p&gt;

&lt;p&gt;The idea of doing it in sequence would be like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get some data fields in the Request Body that the user sends, the purpose is to create a Redis key. Which field to use depends on the business needs, as well as the system architecture that is responding to consider the choice.&lt;/li&gt;
&lt;li&gt;Build the key in some optional format, then hash it again with MD5 (using MD5 here is optional, depending on your needs). If you use it, consider using Fast MD5 for faster speed.&lt;/li&gt;
&lt;li&gt;Every time the user calls the API, the Redis key will be checked. If it exists, a duplicate data error will be returned. If not, the logic will continue to be processed.&lt;/li&gt;
&lt;li&gt;When inserting a key into Redis, an Expired Time must be configured. In the framework of the article, I set it to about 40 seconds for an easy demo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s the idea, but the actual implementation will require a few more techniques, which I will mention later. Let’s build the project and test it first.&lt;/p&gt;

&lt;h4&gt;
  
  
  Project structure
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswqexgn7u5jtpyqh21q5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswqexgn7u5jtpyqh21q5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this project, I using Spring Boot 3.3.4, Java 17, Spring AOP&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1rwymdctzuely69g3pf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1rwymdctzuely69g3pf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the detailed code implementation of each part&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreventDuplicateValidator {

    String[] includeFieldKeys() default {};

    String[] optionalValues() default {};

    long expireTime() default 10_000L;

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PreventDuplicateValidator I declare it as an annotation, here there are three data fields:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;includeFieldKeys:&lt;/strong&gt; to declare the list of fields that are needed to generate the key based on the fields in the Request Body.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;optionalValues:&lt;/strong&gt; a list of values that need to be attached to the key. I implemented this field for the purpose of flexibility in preventing duplication. You can add any data as you like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;expireTime:&lt;/strong&gt; is the key expiration time value, the default is 10 seconds.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.aop;
import com.cafeincode.demo.enums.ErrorCode;
import com.cafeincode.demo.exception.DuplicationException;
import com.cafeincode.demo.exception.HandleGlobalException;
import com.cafeincode.demo.utils.Utils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;

/**
 * author: hungtv27
 * email: hungtvk12@gmail.com
 * blog: cafeincode.com
 */

@Aspect
@Component
@RequiredArgsConstructor
@Slf4jj
public class PreventDuplicateValidatorAspect {

    private final RedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    @Around(value = "@annotation(preventDuplicateValidator)", argNames = "pjp, preventDuplicateValidator")
    public Object aroundAdvice(ProceedingJoinPoint pjp, PreventDuplicateValidator preventDuplicateValidator)
        throws Throwable {

        var includeKeys = preventDuplicateValidator.includeFieldKeys();
        var optionalValues = preventDuplicateValidator.optionalValues();
        var expiredTime = preventDuplicateValidator.expireTime();

        if (includeKeys == null || includeKeys.length == 0) {
            log.warn("[PreventDuplicateRequestAspect] ignore because includeKeys not found in annotation");
            return pjp.proceed();
        }

        //extract request body in request body
        var requestBody = Utils.extractRequestBody(pjp);
        if (requestBody == null) {
            log.warn(
                "[PreventDuplicateRequestAspect] ignore because request body object find not found in method arguments");
            return pjp.proceed();
        }

        //parse request body to map&amp;lt;String, Object&amp;gt;
        var requestBodyMap = convertJsonToMap(requestBody);

        //build key redis from: includeKeys, optionalValues, requestBodyMap
        var keyRedis = buildKeyRedisByIncludeKeys(includeKeys, optionalValues, requestBodyMap);

        //hash keyRedis to keyRedisMD5: this is Optional, should be using Fast MD5 hash to replace
        var keyRedisMD5 = Utils.hashMD5(keyRedis);

        log.info(String.format("[PreventDuplicateRequestAspect] rawKey: [%s] and generated keyRedisMD5: [%s]", keyRedis,
            keyRedisMD5));

        //handle logic check duplicate request by key in Redis
        deduplicateRequestByRedisKey(keyRedisMD5, expiredTime);

        return pjp.proceed();
    }

    private String buildKeyRedisByIncludeKeys(String[] includeKeys, String[] optionalValues, Map&amp;lt;String, Object&amp;gt; requestBodyMap) {

        var keyWithIncludeKey = Arrays.stream(includeKeys)
            .map(requestBodyMap::get)
            .filter(Objects::nonNull)
            .map(Object::toString)
            .collect(Collectors.joining(":"));

        if (optionalValues.length &amp;gt; 0) {
            return keyWithIncludeKey + ":" + String.join(":", optionalValues);
        }
        return keyWithIncludeKey;
    }

    public void deduplicateRequestByRedisKey(String key, long expiredTime) {
        var firstSet = (Boolean) redisTemplate.execute((RedisCallback&amp;lt;Boolean&amp;gt;) connection -&amp;gt;
            connection.set(key.getBytes(), key.getBytes(), Expiration.milliseconds(expiredTime),
                RedisStringCommands.SetOption.SET_IF_ABSENT));

        if (firstSet != null &amp;amp;&amp;amp; firstSet) {
            log.info(String.format("[PreventDuplicateRequestAspect] key: %s has set successfully !!!", key));
            return;
        }
        log.warn(String.format("[PreventDuplicateRequestAspect] key: %s has already existed !!!", key));
        throw new DuplicationException(ErrorCode.ERROR_DUPLICATE.getCode(), ErrorCode.ERROR_DUPLICATE.getMessage());
    }

    public Map&amp;lt;String, Object&amp;gt; convertJsonToMap(Object jsonObject) {
        if (jsonObject == null) {
            return Collections.emptyMap();
        }
        try {
            return objectMapper.convertValue(jsonObject, new TypeReference&amp;lt;&amp;gt;() {
            });
        } catch (Exception ignored) {
            return Collections.emptyMap();
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Here PreventDuplicateValidatorAspect is advice, implementing logic for annotation &lt;em&gt;PreventDuplicateValidator&lt;/em&gt;, I use Around Advice for flexibility&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The logic implementation in the above code is described in the order of steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;First, we will need to extract the request body from the API.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Parse request body into Map format.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Build raw keys from defined data fields.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Build MD5 key&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Check duplicate requests by key&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;If the key already exists in Redis, then throw an exception.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;If the key does not exist in Redis, insert the key into Redis, add the expired time parameter, and then continue the logic of the main function through pjp.proceed()&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
public class BeanConfig {

    @Value("${redis.host}")
    private String redisHost;

    @Value("${redis.port}")
    private int redisPort;

    @Bean(name = "objectMapper")
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        return mapper;
    }

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        var config = new RedisStandaloneConfiguration(redisHost, redisPort);
        return new LettuceConnectionFactory(config);
    }

    @Bean
    @Primary
    public RedisTemplate&amp;lt;Object, Object&amp;gt; redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        var template = new RedisTemplate&amp;lt;&amp;gt;();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BeanConfigI added bean configuration for ObjectMapper and Redis connection bean&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class BaseResponse&amp;lt;T&amp;gt; implements Serializable {

    public static final String OK_CODE = "200";
    public static final String OK_MESSAGE = "Successfully";
    private String code;
    private String message;
    private T data;

    public static &amp;lt;T&amp;gt; BaseResponse&amp;lt;T&amp;gt; ofSucceeded(T data) {
        BaseResponse&amp;lt;T&amp;gt; response = new BaseResponse&amp;lt;&amp;gt;();
        response.code = OK_CODE;
        response.message = OK_MESSAGE;
        response.data = data;
        return response;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BaseResponse is the response class that returns results via API. Large companies as well as standard systems define fields: &lt;strong&gt;&lt;em&gt;code&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;message&lt;/em&gt;&lt;/strong&gt; , and &lt;strong&gt;&lt;em&gt;data&lt;/em&gt;&lt;/strong&gt; in this class (maybe with different names, but not very important).&lt;/p&gt;

&lt;p&gt;We can add other fields depending on usage needs, such as &lt;strong&gt;&lt;em&gt;metadata&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;request_id&lt;/em&gt;&lt;/strong&gt; , etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.dto;
import java.time.Instant;
import lombok.Data;

@Data
public class ProductDto {

    private String productId;
    private String productName;
    private String productDescription;
    private String transactionId;
    private Instant requestTime;
    private String requestId;

}

package com.cafeincode.demo.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum ErrorCode {

    ERROR_DUPLICATE("CF_275", "Duplicated data, please try again later");

    private final String code;
    private final String message;
}

package com.cafeincode.demo.exception;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.HttpStatus;

@Getter
@Setter
@AllArgsConstructor
@Builder
public class DuplicationException extends RuntimeException {

    private String code;
    private String message;
    private HttpStatus httpStatus;

    public DuplicationException(String code, String message) {
        this.code = code;
        this.message = message;
        httpStatus = HttpStatus.BAD_REQUEST;
    }

}

package com.cafeincode.demo.exception;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class HandleGlobalException extends ResponseEntityExceptionHandler {

    @ExceptionHandler(DuplicationException.class)
    private ResponseEntity&amp;lt;?&amp;gt; handleError(Exception ex) {

        //TODO: you should custom more here

        Map&amp;lt;String, String&amp;gt; body = new HashMap&amp;lt;&amp;gt;();
        body.put("code", ((DuplicationException) ex).getCode());
        body.put("message", ex.getMessage());
        return new ResponseEntity&amp;lt;&amp;gt;(body, HttpStatus.BAD_REQUEST);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this class HandleGlobalException, I will handle DuplicationException, the firing in the processing logic from PreventDuplicateValidatorAspect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.service;
import com.cafeincode.demo.dto.ProductDto;

public interface IProductService {

    ProductDto createProduct(ProductDto dto);

}

package com.cafeincode.demo.service;
import com.cafeincode.demo.dto.ProductDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RequiredArgsConstructor
public class ProductService implements IProductService {

    @Override
    public ProductDto createProduct(ProductDto dto) {
        //TODO: more logic here
        return null;
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add more logic if needed; I just need to return null to serve the demo purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.cafeincode.demo.utils;
import jakarta.xml.bind.DatatypeConverter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestBody;

@Slf4j
public class Utils {

    private Utils() {
    }

    public static Object extractRequestBody(ProceedingJoinPoint pjp) {
        try {
            for (int i = 0; i &amp;lt; pjp.getArgs().length; i++) {
                Object arg = pjp.getArgs()[i];
                if (arg != null &amp;amp;&amp;amp; isAnnotatedWithRequestBody(pjp, i)) {
                    return arg;
                }
            }
        } catch (Exception ex) {
            log.error("", ex);
        }
        return null;
    }

    private static boolean isAnnotatedWithRequestBody(ProceedingJoinPoint pjp, int paramIndex) {
        var method = getMethod(pjp);
        var parameterAnnotations = method.getParameterAnnotations();
        for (Annotation annotation : parameterAnnotations[paramIndex]) {
            if (RequestBody.class.isAssignableFrom(annotation.annotationType())) {
                return true;
            }
        }
        return false;
    }

    private static Method getMethod(ProceedingJoinPoint pjp) {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        return methodSignature.getMethod();
    }

    public static String hashMD5(String source) {
        String res = null;
        try {
            var messageDigest = MessageDigest.getInstance("MD5");
            var mdBytes = messageDigest.digest(source.getBytes());
            res = DatatypeConverter.printHexBinary(mdBytes);
        } catch (Exception e) {
            log.error("", e);
        }
        return res;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class Utils includes logic functions to extract the request body from ProceedingJoinPoint and the MD5 hash function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;redis:
  host: localhost
  port: 6379
spring:
  application:
    name: product-service
server:
  port: 8888
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;configure application-local.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.2"
services:
  redis:
    container_name: demo-service-redis
    image: redis:6.2.5
    ports:
      - '6379:6379'

package com.cafeincode.demo.controller;
import com.cafeincode.demo.aop.PreventDuplicateValidator;
import com.cafeincode.demo.dto.BaseResponse;
import com.cafeincode.demo.dto.ProductDto;
import com.cafeincode.demo.service.ProductService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@RequestMapping("/products")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    @PostMapping
    @PreventDuplicateValidator(
        includeFieldKeys = {"productId", "transactionId"},
        optionalValues = {"CAFEINCODE"},
        expireTime = 40_000L)
    public BaseResponse&amp;lt;?&amp;gt; createProduct(@RequestBody ProductDto request) {
        return BaseResponse.ofSucceeded(productService.createProduct(request));
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this main controller section, I declare to use annotation with the parameter values above: PreventDuplicateValidator&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;includeFieldKeys&lt;/strong&gt; : markup will take two fields productIdand transactionId in the request body as input to generate key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;optionalValues&lt;/strong&gt; : option value, I declare here CAFEINCODE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;expireTime&lt;/strong&gt; : data lifetime in Redis cache, I set it to 40 seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Okay, now let’s run the project and test it:&lt;/p&gt;

&lt;p&gt;For MacOS and Windows, you need to turn on Docker Desktop first, then run the command docker-compose up -din Terminal.&lt;/p&gt;

&lt;p&gt;For Ubuntu machines, you need to install Docker first, then run the above command.&lt;/p&gt;

&lt;p&gt;I use a Macbook, and it’s already turned on, so I just need to turn it on to use&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3npim34yif5z8um31fqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3npim34yif5z8um31fqg.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;redis docker&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6v8g7w5z6ulfuflfi94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6v8g7w5z6ulfuflfi94.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;check connection Redis&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Check if the connection to Redis is ok, launch the application&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57h1xav974mpv1w6bgya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57h1xav974mpv1w6bgya.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;config profile local, jdk&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7ahkyllparbhoij55ru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7ahkyllparbhoij55ru.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;start application spring boot&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You open Postman to test, I leave the request body below for you to easily copy and practice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "productId": "hungtv27-test-001",
    "productName": "CAFEINCODE",
    "productDescription": "Threat identify buy war manage little friend south really chair",
    "transactionId": "cd076846-ff28-4307-8524-3eb6e1809838",
    "requestTime": 1696069378367,
    "requestId": "{{$randomUUID}}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg2rmnlv63mikyoq5hin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg2rmnlv63mikyoq5hin.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Sendand follow the results&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9bwedexnk2q0ez12v5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9bwedexnk2q0ez12v5r.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;response when first call&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntpwduzwp85hjb2j8p7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntpwduzwp85hjb2j8p7y.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;validate success, init key to redis&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Check the console log and see the message with the MD5 key: 6C518A2B1666005572EDFC8240A130F2does not exist in Redis, so it will be initialized successfully for the first time and set the expiration time to 40 seconds. Now I will check the data in Redis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxtu1sc1n61boyp3gq3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxtu1sc1n61boyp3gq3e.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;MD5 key in Redis&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The key 6C518A2B1666005572EDFC8240A130F2has been successfully initialized in Redis. Now we will continue to call the API one more time to check the result. The expectation is to return an errorCF_275&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduz8wdhclcg2i7uzg6fk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduz8wdhclcg2i7uzg6fk.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;response when call second&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8d4dt78hz2ox2sb2mav8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8d4dt78hz2ox2sb2mav8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;View the console log to see if the key 6C518A2B1666005572EDFC8240A130F2 already exists in Redis, so it will return error CF_275 to the client.&lt;/p&gt;

&lt;p&gt;So we have completed the implementation of duplicate prevention based on Redis and Spring AOP. In this article, there are some conclusions that you need to consider as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Select appropriate parameter fields in the Request Body to be used as an input source to create a key; you should ignore time-type fields such as createTime or updateTime.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Set the expiration time value to suit the project's business needs.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Consider whether to hash MD5 or not. If you want to optimize performance, you can remove or choose to use Fast MD5&lt;/em&gt;&lt;/strong&gt; (I do not use it in this article).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, after implementing the complete logic, all we need to do is declare annotation on the controllers that we need to use. Setting the data fields is very flexible, so we rarely need to modify anything further.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thanks, before you go:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;👏 If you have any better solutions, please comment below, we will discuss and learn from each other.&lt;/p&gt;

&lt;p&gt;👏 Please clap for the story and follow the author, 👉👉👉 &lt;a href="https://medium.com/@hungtvk12" rel="noopener noreferrer"&gt;hungtv27&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👏 Please share your questions or insights in the comments section below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://cafeincode.com/how-to-prevent-duplicate-request-effectively/" rel="noopener noreferrer"&gt;&lt;em&gt;https://cafeincode.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on October 1, 2024.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>redis</category>
      <category>springboot3</category>
      <category>deduplication</category>
      <category>java17</category>
    </item>
    <item>
      <title>Stop using if-else statements in Java</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Tue, 20 Aug 2024 08:59:28 +0000</pubDate>
      <link>https://dev.to/hungtvk12/stop-using-if-else-statements-in-java-43k3</link>
      <guid>https://dev.to/hungtvk12/stop-using-if-else-statements-in-java-43k3</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8vij7f0gcbq3xon0we8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8vij7f0gcbq3xon0we8.png" width="676" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tale goes that there is an ancient legacy system, my colleague coded thousands of lines from top to bottom, and each block added several if then java sections to route circumstances, so I feel like I’m trapped in an unfamiliar fairyland.&lt;/p&gt;

&lt;p&gt;In this post, I will show you how to optimize the use of if-else, restrict code with too many branching conditions, and make your Java code much easier to read and understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code snippets with too many if-else statements
&lt;/h3&gt;

&lt;p&gt;Before delving into the details of optimization, let’s use a sample demo Java code with multiple if else conditions, and then optimize it in various ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ShippingCostCalculator {
    public double calculateShippingCost(String shippingType, double weight) {
        if (shippingType.equals("STANDARD")) {
            return weight * 5.0;
        } else if (shippingType.equals("EXPRESS")) {
            return weight * 10.0;
        } else if (shippingType.equals("SAME_DAY")) {
            return weight * 20.0;
        } else if (shippingType.equals("INTERNATIONAL")) {
            return weight * 50.0;
        } else if (shippingType.equals("OVERNIGHT")) {
            return weight * 30.0;
        }
        return 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the code above calculates shipping charges based on the shipping type&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimize using Enum
&lt;/h3&gt;

&lt;p&gt;Now, we will use Enumto replace the statements if-else&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum ShippingType {
    STANDARD {
        @Override
        public double getCost(double weight) {
            return weight * 5.0;
        }
    },
    EXPRESS {
        @Override
        public double getCost(double weight) {
            return weight * 10.0;
        }
    },
    SAME_DAY {
        @Override
        public double getCost(double weight) {
            return weight * 20.0;
        }
    },
    INTERNATIONAL {
        @Override
        public double getCost(double weight) {
            return weight * 50.0;
        }
    },
    OVERNIGHT {
        @Override
        public double getCost(double weight) {
            return weight * 30.0;
        }
    };

    public abstract double getCost(double weight);
}

public class ShippingCostCalculator {

    public double calculateShippingCost(ShippingType shippingType, double weight) {
        return shippingType.getCost(weight);
    }
}

public class MainCost {
    public static void main(String[] args) {
        var calculator = new ShippingCostCalculator();
        var cost = calculator.calculateShippingCost(ShippingType.EXPRESS, 2.5);
        System.out.println("Shipping cost: " + cost);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the difficult if-else statement has been simplified into two short, straightforward lines of code. Run the main function to see the results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6yf6xirid3ixmsaz0qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6yf6xirid3ixmsaz0qh.png" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantage&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extensibility: Add new shipping types and values. Enumerate and define a handling method for it.&lt;/li&gt;
&lt;li&gt;Maintainable and understandable code: The reasoning for each method of transport is isolated and easy to comprehend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;However&lt;/strong&gt; , utilizing Enum has certain clear downsides that you should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt; : Add new shipping types and values. Enumerate and define a handling method for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficult to add new parameters&lt;/strong&gt; : When more parameters are needed, Enum is not well-suited, and the code becomes cumbersome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance restrictions&lt;/strong&gt; : Enum cannot inherit from other classes, which reduces their potential to reuse logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Enum for optimization is generally suitable in simple case conditions with few parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimization with Factory Pattern
&lt;/h3&gt;

&lt;p&gt;Still the messy code above, we will optimize it in the following way:&lt;/p&gt;

&lt;p&gt;Create an Interface ShippingCostStrategy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface ShippingCostStrategy {
    double calculate(double weight);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will create specific classes for each type of delivery, implementing the interface above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class StandardShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 5.0;
    }
}

public class ExpressShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 10.0;
    }
}

public class SameDayShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 20.0;
    }
}

public class InternationalShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 50.0;
    }
}

public class OvernightShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 30.0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will create a Factory class to handle routing to Strategies based on shipping type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.HashMap;
import java.util.Map;

public class ShippingCostFactory {
    private static final Map&amp;lt;String, ShippingCostStrategy&amp;gt; strategies = new HashMap&amp;lt;&amp;gt;();

    static {
        strategies.put("STANDARD", new StandardShipping());
        strategies.put("EXPRESS", new ExpressShipping());
        strategies.put("SAME_DAY", new SameDayShipping());
        strategies.put("INTERNATIONAL", new InternationalShipping());
        strategies.put("OVERNIGHT", new OvernightShipping());
    }

    public static ShippingCostStrategy getStrategy(String shippingType) {
        ShippingCostStrategy strategy = strategies.get(shippingType);
        if (strategy == null) {
            throw new IllegalArgumentException("Invalid shipping type: " + shippingType);
        }
        return strategy;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now just call it and use it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ShippingCostCalculator {
    public double calculateShippingCost(String shippingType, double weight) {
        ShippingCostStrategy strategy = ShippingCostFactory.getStrategy(shippingType);
        return strategy.calculate(weight);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://javarevisited.substack.com/p/beat-90-of-candidates-software-engineers" rel="noopener noreferrer"&gt;Beat 90% of Candidates: Software Engineer's Fast-Track Coding Interview Guide&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of Factory Pattern:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy extensibility&lt;/strong&gt; : Add new delivery kinds by simply developing additional classes and updating the Factory without changing the core code.
&lt;strong&gt;Logical separation&lt;/strong&gt; : Charging logic is segregated, and simple to manage and maintain.
&lt;strong&gt;Flexibility&lt;/strong&gt; : The factory might return multiple solutions depending on other factors, increasing flexibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimization using Strategy Pattern
&lt;/h3&gt;

&lt;p&gt;Before we get into detail, please keep in mind that the implementation will be similar to Factory, but the purpose of use will be slightly different&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface ShippingCostStrategy {
    double calculate(double weight);
}

public class StandardShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 5.0;
    }
}

public class ExpressShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 10.0;
    }
}

public class SameDayShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 20.0;
    }
}

public class InternationalShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 50.0;
    }
}

public class OvernightShipping implements ShippingCostStrategy {
    @Override
    public double calculate(double weight) {
        return weight * 30.0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will create ShippingContext to manage strategies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ShippingCostContext {
    private ShippingCostStrategy strategy;

    public void setStrategy(ShippingCostStrategy strategy) {
        this.strategy = strategy;
    }

    public double calculateShippingCost(double weight) {
        return strategy.calculate(weight);
    }
}

import java.util.HashMap;
import java.util.Map;

public class ShippingCostCalculator {

    private static final Map&amp;lt;String, ShippingCostStrategy&amp;gt; strategies = new HashMap&amp;lt;&amp;gt;();

    static {
        strategies.put("STANDARD", new StandardShipping());
        strategies.put("EXPRESS", new ExpressShipping());
        strategies.put("SAME_DAY", new SameDayShipping());
        strategies.put("INTERNATIONAL", new InternationalShipping());
        strategies.put("OVERNIGHT", new OvernightShipping());
    }

    private final ShippingCostContext context = new ShippingCostContext();

    public double calculateShippingCost(String shippingType, double weight) {
        ShippingCostStrategy strategy = strategies.get(shippingType);
        if (strategy == null) {
            throw new IllegalArgumentException("Invalid shipping type: " + shippingType);
        }
        context.setStrategy(strategy);
        return context.calculateShippingCost(weight);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, add it inside the Main Class to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MainCost {

    public static void main(String[] args) 
        ShippingCostCalculator calculator = new ShippingCostCalculator();

        double weight = 10.0;

        String shippingType1 = "STANDARD";
        double cost1 = calculator.calculateShippingCost(shippingType1, weight);
        System.out.println("Shipping cost for " + shippingType1 + ": " + cost1);

        String shippingType2 = "EXPRESS";
        double cost2 = calculator.calculateShippingCost(shippingType2, weight);
        System.out.println("Shipping cost for " + shippingType2 + ": " + cost2);

        String shippingType3 = "SAME_DAY";
        double cost3 = calculator.calculateShippingCost(shippingType3, weight);
        System.out.println("Shipping cost for " + shippingType3 + ": " + cost3);

        String shippingType4 = "INTERNATIONAL";
        double cost4 = calculator.calculateShippingCost(shippingType4, weight);
        System.out.println("Shipping cost for " + shippingType4 + ": " + cost4);

        String shippingType5 = "OVERNIGHT";
        double cost5 = calculator.calculateShippingCost(shippingType5, weight);
        System.out.println("Shipping cost for " + shippingType5 + ": " + cost5);
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagmlkvklz6og8meuetlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagmlkvklz6og8meuetlx.png" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous two cases, the Strategy Pattern manages how shipping costs are computed, and the Factory Pattern decides which strategy to utilize based on the delivery type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimize using Stream API and Map
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.HashMap;
import java.util.Map;

public class ShippingCostCalculator {

    private static final Map&amp;lt;String, Double&amp;gt; shippingCosts = new HashMap&amp;lt;&amp;gt;();

    static {
        shippingCosts.put("STANDARD", 5.0);
        shippingCosts.put("EXPRESS", 10.0);
        shippingCosts.put("SAME_DAY", 20.0);
        shippingCosts.put("INTERNATIONAL", 50.0);
        shippingCosts.put("OVERNIGHT", 30.0);
    }

    public double calculateShippingCost(String shippingType, double weight) {
        return shippingCosts.entrySet().stream()
            .filter(entry -&amp;gt; entry.getKey().equalsIgnoreCase(shippingType))
            .map(Map.Entry::getValue)
            .findFirst()
            .orElse(0.0)
            * weight; 
    }

    public static void main(String[] args) {
        ShippingCostCalculator calculator = new ShippingCostCalculator();

        double weight = 10.0;

        String shippingType1 = "STANDARD";
        double cost1 = calculator.calculateShippingCost(shippingType1, weight);
        System.out.println("Shipping cost for " + shippingType1 + ": " + cost1);

        String shippingType2 = "EXPRESS";
        double cost2 = calculator.calculateShippingCost(shippingType2, weight);
        System.out.println("Shipping cost for " + shippingType2 + ": " + cost2);

        String shippingType3 = "SAME_DAY";
        double cost3 = calculator.calculateShippingCost(shippingType3, weight);
        System.out.println("Shipping cost for " + shippingType3 + ": " + cost3);

        String shippingType4 = "INTERNATIONAL";
        double cost4 = calculator.calculateShippingCost(shippingType4, weight);
        System.out.println("Shipping cost for " + shippingType4 + ": " + cost4);

        String shippingType5 = "OVERNIGHT";
        double cost5 = calculator.calculateShippingCost(shippingType5, weight);
        System.out.println("Shipping cost for " + shippingType5 + ": " + cost5);

        String invalidType = "INVALID";
        double invalidCost = calculator.calculateShippingCost(invalidType, weight);
        System.out.println("Shipping cost for " + invalidType + ": " + invalidCost);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44s41p03yo4y8donuyfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44s41p03yo4y8donuyfc.png" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This strategy is also quite convenient; while the expansion is not as good as Factory and Strategy, it is still a viable option for simple scenarios.&lt;/p&gt;

&lt;p&gt;Thanks, before you go:&lt;/p&gt;

&lt;p&gt;👏 Please clap for the story and follow the author 👉&lt;br&gt;&lt;br&gt;
Please share your questions or insights in the comments section below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://cafeincode.com/stop-using-if-else-statements-in-java/" rel="noopener noreferrer"&gt;&lt;em&gt;https://cafeincode.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on August 20, 2024.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>java</category>
      <category>javabestpractices</category>
      <category>java8</category>
    </item>
    <item>
      <title>Best practices for using Java Stream</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Wed, 17 Apr 2024 15:58:56 +0000</pubDate>
      <link>https://dev.to/hungtvk12/best-practices-for-using-java-stream-2935</link>
      <guid>https://dev.to/hungtvk12/best-practices-for-using-java-stream-2935</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzlnvp9aqc2q0wiwc8qj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzlnvp9aqc2q0wiwc8qj.jpg" width="676" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When working with Java, understanding and knowing how to use &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html" rel="noopener noreferrer"&gt;streams&lt;/a&gt; to optimize work performance is necessary. Today I will show you how to use some of the functions that Java streams provide, helping Your code become more visible and elegant.&lt;/p&gt;

&lt;p&gt;First, let’s go through the popular functions that Java Stream provides.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;filter&lt;/strong&gt; removes elements that do not satisfy the predicate filter condition, or in other words, retains elements that satisfy the filter condition&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.stream.Collectors;

public class CafeincodeExample {

    public static void main(String[] args) {
        var domains = Arrays.asList("cafeincode", "medium", "google");
        var filtered = domains.stream()
                .filter(item -&amp;gt; item.startsWith("c"))
                .peek(item -&amp;gt; System.out.println("Result: " + item))
                .collect(Collectors.toList());
    }
}

Result: cafeincode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;map&lt;/strong&gt; is responsible for mapping each element in the stream to another data type through the function you specify and creating a new stream, like in the example below, I use the available toUpperCase function&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.stream.Collectors;

public class CafeincodeExample {

    public static void main(String[] args) {
        var input = Arrays.asList("cafeincode", "medium", "google");
        var mapped = input.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("Result: " + mapped);
    }
}

Result: [CAFEINCODE, MEDIUM, GOOGLE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;flatMap&lt;/strong&gt; is used to process the elements of a stream and help transform them into a new stream or a list of elements, i.e. it will combine child streams into a parent stream.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CafeincodeExample {

    public static void main(String[] args) {
        var nestedNumbers = Arrays.asList(
                Arrays.asList(1, 2),
                Arrays.asList(3, 4),
                Arrays.asList(5, 6)
        );
        var flattenedNumbers = nestedNumbers.stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());
        System.out.println("Result: " + flattenedNumbers);
    }
}

Result: [1, 2, 3, 4, 5, 6]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;distinct&lt;/strong&gt; is used to remove duplicate elements from a stream and it will return a new stream containing only unique elements&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.stream.Collectors;

public class CafeincodeExample {

    public static void main(String[] args) {
        var numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5, 5);
        var distinctNumbers = numbers.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("Result: " + distinctNumbers);
    }
}

Result: [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;sorted&lt;/strong&gt; is used to sort the elements of a stream in a certain order and will return a new stream containing the sorted elements&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.stream.Collectors;

public class CafeincodeExample {

    public static void main(String[] args) {
        var numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5);
        var sortedNumbers = numbers.stream()
                .sorted()
                .collect(Collectors.toList());
        System.out.println("Result: " + sortedNumbers);
    }
}

Result: [1, 1, 2, 3, 4, 5, 5, 6, 9]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;peek&lt;/strong&gt; is often used to perform debugging or logging operations on elements during stream processing without changing the content of the stream.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {

    public static void main(String[] args) {
        IntStream.range(1, 6)
                .peek(element -&amp;gt; System.out.println("Processing element: " + element))
                .map(CafeincodeExample::mapping)
                .forEach(System.out::println);
    }

    private static Integer mapping(Integer input) {
        return input * input;
    }
}

Processing element: 1
1
Processing element: 2
4
Processing element: 3
9
Processing element: 4
16
Processing element: 5
25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;limit&lt;/strong&gt; is used to limit the number of elements in a stream, it will return a new stream containing the number of elements limited to a certain value.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {

    public static void main(String[] args) {
        IntStream.range(1, 100)
                .limit(5)
                .forEach(System.out::println);
    }
}

1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;skip&lt;/strong&gt; is used to skip a certain number of elements in a stream and return a new stream starting from the position that was skipped&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {

    public static void main(String[] args) {
        IntStream.range(1, 11)
                .skip(5)
                .forEach(System.out::println);
    }
}

6
7
8
9
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, IntStream.range(1, 11)create a Stream containing the numbers 1 to 10.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;skip(5)used to skip the first 5 elements of the stream&lt;/li&gt;
&lt;li&gt;forEach(System.out::println)used to print out the remaining elements of the stream, starting from the 6th element to the last element&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;toArray&lt;/strong&gt; is used to convert a stream into an array, this method returns an array containing the elements of the stream in order.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {

    public static void main(String[] args) {
        int[] numbers = IntStream.range(1, 6)
                .toArray();

        for (int number : numbers) {
            System.out.println("Result: " + number);
        }
    }
}

Result: 1
Result: 2
Result: 3
Result: 4
Result: 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;reduce&lt;/strong&gt; is used to perform a transformation on the elements of the stream to calculate a final value&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;

public class CafeincodeExample {

    public static void main(String[] args) {
        Integer[] integers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        var result = Arrays.stream(integers).reduce(0, Integer::sum);
        System.out.println("Result: " + result);
    }
}

Result: 55
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;collect&lt;/strong&gt; is used to collect the elements of a stream into a specific data structure, such as a List, Set or Map&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5);
        var list = stream.collect(Collectors.toList());
        System.out.println("Result: " + list);
    }
}

Result: [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;count&lt;/strong&gt; is used to count the number of elements in a stream, this method returns an integer value that is the number of elements in the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {

        var stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 11);
        var count = stream.count();
        System.out.println("Result: " + count);
    }
}

Result: 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;anyMatch&lt;/strong&gt; is used to check whether at least one element in the stream satisfies the condition&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of("apple", "banana", "orange", "grape", "kiwi");
không
        var anyMatch = stream.anyMatch(str -&amp;gt; str.startsWith("a"));

        if (anyMatch) {
            System.out.println("There are elements starting with the letter 'a' in Stream");
        } else {
            System.out.println("There are no elements starting with the letter 'a' in Stream");
        }
    }
}

There are elements starting with the letter 'a' in Stream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;allMatch&lt;/strong&gt; is used to check whether all elements in the stream satisfy the given condition&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of(2, 4, 6, 8, 10);
        var allMatch = stream.allMatch(number -&amp;gt; number % 2 == 0);

        if (allMatch) {
            System.out.println("Result: All numbers in the Stream are divisible by 2");
        } else {
            System.out.println("Result: There is at least one number in the Stream that is not divisible by 2");
        }
    }
}

Result: All numbers in the Stream are divisible by 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;noneMatch&lt;/strong&gt; it still returns a boolean value, however, this function will check that all elements in the stream must not satisfy a condition.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of(2, 4, 6, 8, 10);
        var noneMatch = stream.noneMatch(number -&amp;gt; number % 5 == 0);

        if (noneMatch) {
            System.out.println("Result: There are no numbers in the Stream that are divisible by 5");
        } else {
            System.out.println("Result: There is at least one number in the Stream that is divisible by 5");
        }
    }
}

Result: There is at least one number in the Stream that is divisible by 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;findFirst&lt;/strong&gt; returns the first element in the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Optional;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of("apple", "banana", "cherry", "avocado", "blueberry");
        Optional&amp;lt;String&amp;gt; firstElement = stream.findFirst();
        if (firstElement.isPresent()) {
            System.out.println("Result: First element: " + firstElement.get());
        } else {
            System.out.println("Result: Stream is empty.");
        }
    }
}

Result: First element: apple
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;findAny&lt;/strong&gt; returns any element in the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Optional;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of("apple", "banana", "cherry", "avocado", "blueberry");
        Optional&amp;lt;String&amp;gt; anyElement = stream.findAny();
        if (anyElement.isPresent()) {
            System.out.println("Result: Any element: " + anyElement.get());
        } else {
            System.out.println("Result: Stream is empty.");
        }
    }
}

Result: Any element: apple
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;min&lt;/strong&gt; returns the smallest word in the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Optional;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of(5, 2, 8, 1, 3);

        Optional&amp;lt;Integer&amp;gt; minElement = stream.min(Integer::compareTo);

        if (minElement.isPresent()) {
            System.out.println("Minimum element: " + minElement.get());
        } else {
            System.out.println("Stream is empty.");
        }
    }
}

Minimum element: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;max&lt;/strong&gt; returns the largest element in the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Optional;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of(5, 2, 8, 1, 3);

        Optional&amp;lt;Integer&amp;gt; maxElement = stream.max(Integer::compareTo);

        if (maxElement.isPresent()) {
            System.out.println("Maximum element: " + maxElement.get());
        } else {
            System.out.println("Stream is empty.");
        }
    }
}

Maximum element: 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;groupingBy&lt;/strong&gt; is used to group elements in the stream according to a certain condition&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CafeincodeExample {

    public static void main(String[] args) {
        var stream = Stream.of("apple", "banana", "cherry", "avocado", "blueberry");
        var groupedByLength = stream.collect(Collectors.groupingBy(String::length));
        System.out.println("Result: " + groupedByLength);
    }
}

Result: {5=[apple], 6=[banana, cherry], 7=[avocado], 9=[blueberry]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;partitioningBy&lt;/strong&gt; is used to divide the stream elements into two groups based on a provided condition, the return result is a Map with two keys: true and false&lt;/p&gt;

&lt;p&gt;Elements that satisfy the condition will be assigned to the key true and elements that do not satisfy the condition will be assigned to the key false&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Map&amp;lt;Boolean, List&amp;lt;Integer&amp;gt;&amp;gt; partitioned = stream.collect(Collectors.partitioningBy(i -&amp;gt; i % 2 == 0));
        System.out.println("Even numbers: " + partitioned.get(true));
        System.out.println("Odd numbers: " + partitioned.get(false));
    }
}

Even numbers: [2, 4, 6, 8, 10] 
Odd numbers: [1, 3, 5, 7, 9]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;joining&lt;/strong&gt; is used to combine stream elements into one string, you can provide a separating string between elements or leave it as default&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Arrays;
import java.util.stream.Collectors;

public class CafeincodeExample {
    public static void main(String[] args) {
        var data = Arrays.asList("apple", "banana", "cherry");
        String result = data.stream().collect(Collectors.joining(", "));
        System.out.println("Result: " + result);
    }
}

Result: apple, banana, cherry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Iterating&lt;/strong&gt; is often used when it is necessary to create a sequence of values ​​​​generated according to a certain rule&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; evenNumbers = Stream.iterate(2, n -&amp;gt; n + 2).limit(5);
        evenNumbers.forEach(System.out::println);
    }
}

2
4
6
8
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;of&lt;/strong&gt; is used to create a stream from the elements provided as arguments&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;String&amp;gt; stream = Stream.of("apple", "banana", "cherry");
        stream.forEach(System.out::println);
    }
}

apple 
banana 
cherry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;concat&lt;/strong&gt; is used to concatenate two streams together, creating a new stream containing all the elements of the two original streams&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;String&amp;gt; stream1 = Stream.of("apple", "banana");
        Stream&amp;lt;String&amp;gt; stream2 = Stream.of("cherry", "grape");
        Stream&amp;lt;String&amp;gt; concatenatedStream = Stream.concat(stream1, stream2);
        concatenatedStream.forEach(System.out::println);
    }
}

apple
banana
cherry
grape
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;unordered&lt;/strong&gt; is used to specify that the stream will not follow the originally defined order.&lt;/p&gt;

&lt;p&gt;This means that elements in the stream can appear in any order after performing transformations or collecting on the stream&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5);

        Stream&amp;lt;Integer&amp;gt; unorderedStream = stream.unordered();


        unorderedStream.forEach(System.out::println);
    }
}

1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;range is used to create a stream containing consecutive integers, starting at a value A and ending at a value B-1&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {
    public static void main(String[] args) {
        IntStream rangeStream = IntStream.range(1, 6);

        rangeStream.forEach(System.out::println);
    }
}

1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;rangeClosed&lt;/strong&gt; is used to create a stream with integers in the range A to B&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;

public class CafeincodeExample {
    public static void main(String[] args) {
        IntStream rangeClosedStream = IntStream.rangeClosed(1, 5);
        rangeClosedStream.forEach(System.out::println);
    }
}

1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;generate&lt;/strong&gt; is used to generate a stream by generating elements based on a provided supplier, which independently generates elements each time it is called&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;String&amp;gt; stream = Stream.generate(() -&amp;gt; "Cafeincode").limit(3);
        stream.forEach(System.out::println);
    }
}

Cafeincode
Cafeincode
Cafeincode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;takeWhile&lt;/strong&gt; is used to retrieve elements from a stream until a condition is no longer satisfied.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Stream&amp;lt;Integer&amp;gt; takenStream = stream.takeWhile(n -&amp;gt; n &amp;lt;= 7);
        takenStream.forEach(System.out::println);
    }
}

1
2
3
4
5
6
7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In contrast to takeWhile, &lt;strong&gt;dropWhile&lt;/strong&gt; is used to remove elements from a stream until a condition is no longer satisfied, the remainder of the stream will be elements that do not satisfy the condition&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Stream&amp;lt;Integer&amp;gt; droppedStream = stream.dropWhile(n -&amp;gt; n &amp;lt;= 6);
        droppedStream.forEach(System.out::println);
    }
}

7
8
9
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;boxed&lt;/strong&gt; is used to convert the elements of a stream from primitive types to boxed types, which is useful when you want to work with streams of objects instead of primitive types&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.IntStream;
import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        IntStream intStream = IntStream.of(1, 2, 3, 4, 5, 6, 7, 8);
        Stream&amp;lt;Integer&amp;gt; boxedStream = intStream.boxed();
        boxedStream.forEach(System.out::println);
    }
}

1
2
3
4
5
6
7
8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;parallel&lt;/strong&gt; used to convert a stream into a stream that can be processed in parallel.&lt;/p&gt;

&lt;p&gt;When a stream is processed in parallel, elements of the stream can be processed on multiple threads simultaneously, increasing application performance on systems with multiple processors.&lt;/p&gt;

&lt;p&gt;However, in reality, using parallel in some cases does not really bring much significant performance, you can learn more about this part yourself.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; stream = Stream.of(1, 2, 3, 4, 5);
        Stream&amp;lt;Integer&amp;gt; parallelStream = stream.parallel();
        parallelStream.forEach(System.out::println);
    }
}

3
5
4
2
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;sequential&lt;/strong&gt; used to convert a stream from parallel processing to sequential processing.&lt;/p&gt;

&lt;p&gt;When a stream is processed sequentially, the stream’s elements are processed in order from start to finish on a single stream.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.stream.Stream;

public class CafeincodeExample {
    public static void main(String[] args) {
        Stream&amp;lt;Integer&amp;gt; parallelStream = Stream.of(1, 2, 3, 4, 5).parallel();
        Stream&amp;lt;Integer&amp;gt; sequentialStream = parallelStream.sequential();
        sequentialStream.forEach(System.out::println);
    }
}

1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best practice in using Java streams
&lt;/h3&gt;

&lt;p&gt;Using streams properly makes your code more elegant, easier to see, and neater than the traditional coding style.&lt;/p&gt;

&lt;p&gt;However, it must be said again and again, that too much of anything is not necessarily good. Overusing streams or confusing writing methods will also give you a real headache every time you debug.&lt;/p&gt;

&lt;p&gt;So below are some best practices that I think should be applied to both make good use of it and avoid unnecessary abuse.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When using a stream where multiple methods are continuously applied, put each function on a different line, it will be extremely useful when debugging.&lt;/li&gt;
&lt;li&gt;Use the methods I listed above map(), filter(), reduce(), collect(),... appropriately to perform operations on the stream&lt;/li&gt;
&lt;li&gt;Check for &lt;strong&gt;null&lt;/strong&gt; during map and filter operations&lt;/li&gt;
&lt;li&gt;Avoid overusing &lt;strong&gt;parallel&lt;/strong&gt; in the coding process, in many cases it does not achieve as much performance value as you think. If possible, just use the default &lt;strong&gt;sequential&lt;/strong&gt; only.&lt;/li&gt;
&lt;li&gt;Name variables when used appropriately. Do not use variable names with the default letters a, b, and c because it will be difficult to understand when reading.&lt;/li&gt;
&lt;li&gt;Using Optional makes sense in cases where findFirst or findAny are used&lt;/li&gt;
&lt;li&gt;In reality, there will be many methods you need to re-implement rather than using the default, for example,  &lt;strong&gt;sorted&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Peek&lt;/strong&gt; to debug properly&lt;/li&gt;
&lt;li&gt;In the case of converting &lt;strong&gt;List&lt;/strong&gt; to &lt;strong&gt;Map&lt;/strong&gt; , you need to be careful to pay attention to duplicate keys&lt;/li&gt;
&lt;li&gt;Java streams use lazy evaluation (discussed in another article), which means elements are only calculated when necessary. You can use this to increase performance by avoiding unnecessary calculations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks, before you go:&lt;/p&gt;

&lt;p&gt;👏 Please clap for the story and follow the author 👉&lt;br&gt;&lt;br&gt;
Please share your questions or insights in the comments section below.&lt;br&gt;&lt;br&gt;
Let’s connect on &lt;a href="https://www.linkedin.com/in/hungtv27" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://dev.to/hungtvk12/best-practice-trong-viec-su-dung-java-stream-1edn-temp-slug-7107213"&gt;&lt;em&gt;https://cafeincode.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on April 17, 2024.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>javastreams</category>
      <category>bestpracticeusingjav</category>
    </item>
    <item>
      <title>Take advantage of scripts in Postman to save your time</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Sun, 24 Mar 2024 05:48:36 +0000</pubDate>
      <link>https://dev.to/hungtvk12/take-advantage-of-scripts-in-postman-to-save-your-time-504h</link>
      <guid>https://dev.to/hungtvk12/take-advantage-of-scripts-in-postman-to-save-your-time-504h</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0z4scl5g0ty2mw301t9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0z4scl5g0ty2mw301t9j.png" width="676" height="295"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;effectively utilizing Postman scripts&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my work process, using &lt;a href="https://learning.postman.com/docs/writing-scripts/intro-to-scripts/" rel="noopener noreferrer"&gt;Postman script&lt;/a&gt; to test API terminals is almost indispensable in my work process. In this article, I will share a few good ways to optimize my time. you guys when testing the API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use scripts to create virtual data
&lt;/h3&gt;

&lt;p&gt;When testing the API, you will need fake data sets to use as input data, perhaps passing in the request body, request param, or path variable, but you don’t want to have to change it manually. automatically randomize the value.&lt;/p&gt;

&lt;p&gt;In Postman, there are already random functions that help you automatically create fake value sets. All we need to do is take them out to use, you can see below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "{{$randomFullName}}",
    "gender": "MALE",
    "first_name": "{{$randomWord}}",
    "last_middle_name": "{{$randomWord}}",
    "identify_number": "{{$randomBankAccount}}",
    "permanent_address": "{{$randomStreetAddress}}",
    "self_description": "{{$randomWords}}",
    "bank_account_holder": "{{$randomBankAccountName}}",
    "bank_account_number": "{{$randomBankAccount}}",
    "bank_code": "{{$randomBankAccount}}",
    "bank_name": "{{$randomBankAccountName}}",
    "tax_code": "{{$randomBankAccount}}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5y1h2t6ggz9ivkd3qxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5y1h2t6ggz9ivkd3qxb.png" width="640" height="369"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;using random method in the Postman tool&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Or instead of using Postman’s built-in random functions, you can write your own function and create your own variables to use for your needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Random phone number
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const prefixes = ['03', '05', '07', '08', '09']; 
const randomPrefix = prefixes[Math.floor(Math.random() * prefixes.length)]; 
let phoneNumber = randomPrefix + Math.random().toString().slice(2, 10); 
pm.environment.set("randomPhoneNumber", phoneNumber); 
console.log("Random phone number:", phoneNumber);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfgnakp3lrj5okuxehzk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfgnakp3lrj5okuxehzk.png" width="674" height="164"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;random phone number script&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Random full name
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const lastNames = ["Nguyễn", "Trần", "Lê", "Phạm", "Hoàng", "Huỳnh", "Phan", "Vũ", "Võ", "Đặng", "Bùi", "Đỗ", "Hồ", "Ngô", "Dương", "Lý", "Đào", "Đoàn", "Đinh", "Lương"]; 
const firstNames = ["An", "Bình", "Châu", "Duy", "Giang", "Hải", "Hà", "Hạnh", "Hiếu", "Hoàng", "Huy", "Khoa", "Lan", "Linh", "Long", "Minh", "Nam", "Nga", "Nhi", "Như", "Phong", "Phương", "Quân", "Quốc", "Sơn", "Thảo", "Thành", "Thu", "Thủy", "Tiến", "Trang", "Trung", "Tùng", "Tú", "Tuấn", "Uyên", "Vân", "Việt", "Xuân", "Yến"]; 
function generateRandomFullName() { 
  const randomLastNameIndex = Math.floor(Math.random() * lastNames.length); 
  const randomFirstNameIndex = Math.floor(Math.random() * firstNames.length); 
  const fullName = lastNames[randomLastNameIndex] + " " + firstNames[randomFirstNameIndex];
 return fullName; 
} 
const randomFullName = generateRandomFullName(); 
pm.environment.set("randomFullName", randomFullName); 
console.log("Random full name:", randomFullName);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fts1ivni8e97fwwlnroel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fts1ivni8e97fwwlnroel.png" width="800" height="279"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;random full name script&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Random email
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const domains = ["gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "icloud.com", "aol.com", "protonmail.com", "mail.com", "zoho.com", "yandex.com"]; 
function generateRandomEmail() { 
  const randomUsername = Math.random().toString(36).substring(7); 
  const randomDomain = domains[Math.floor(Math.random() * domains.length)]; 
  const email = randomUsername + "@" + randomDomain; 
  return email; 
} 
const randomEmail = generateRandomEmail(); 
console.log("Random email:", randomEmail); 
pm.environment.set("randomEmail", randomEmail);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywmsvx94d488jb8y7vlz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywmsvx94d488jb8y7vlz.png" width="800" height="158"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;random email script&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Random gender
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function generateRandomGender() { 
  const genders = ["MALE", "FEMALE", "OTHER"]; 
  const randomIndex = Math.floor(Math.random() * genders.length); 
  const randomGender = genders[randomIndex]; 
  return randomGender; 
} 
const randomGender = generateRandomGender(); 
pm.environment.set("randomGender", randomGender); 
console.log("Random gender:", randomGender);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22hnt1fbeydejqk5sczt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22hnt1fbeydejqk5sczt.png" width="685" height="256"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;random gender script&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can reuse the above scripts or optimize them according to your actual needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Write a script to get data from the response and transmit it to other APIs
&lt;/h3&gt;

&lt;p&gt;Now after getting the results from the API, you want to throw some values ​​from response API A to the request body or request param of API B, C, D, E, or something else to call again, but you don’t want to. Copying manually by hand it is very tiring.&lt;/p&gt;

&lt;p&gt;The most effective way is to write functions to extract data from the response, then pass the extracted value results into parameter variables, and then use these parameter variables on the APIs that need to be called.&lt;/p&gt;

&lt;p&gt;Some use cases you can often use are:&lt;/p&gt;
&lt;h3&gt;
  
  
  Get access token from login API
&lt;/h3&gt;

&lt;p&gt;The example below is the resulting JSON string after making a call to the login API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMzjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjIsInJvbGUiOiJ1c2VyIn0.DeOXN2oxXntRklB5A9IMop0EXo-qYpBJE7Je9y06X5o",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJlreHAiOjE1MTYyMzkwMjIsInJvbGUiOiJ1c2VyIn0.S8EoXZBk7oG3K9TThlTMyhYO2XvE7YlzzI6xgJgrXhg",
    "scope": "read write",
    "user_id": "1234567890"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will need to write a function to get that access_token value and put it into another API to call&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go to the Tests&lt;/strong&gt; tab in Postman to write the script below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log('Request:'+ pm.request.body.toString()) 
var jsonData = pm.response.json(); 
var accessToken = jsonData.access_token; 
pm.environment.set("accessToken", accessToken); 
console.log('Token:'+ accessToken)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the access_token value from the login API has been passed into the variable accessToken, you just need to take it out and use it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4flle7thd7f6me07xk37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4flle7thd7f6me07xk37.png" width="800" height="234"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;using variable accessToken&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Get an array of a list of data
&lt;/h3&gt;

&lt;p&gt;Just imagine, if you need to test 7 or 8 APIs continuously, each API needs data from the previous API. At that time, having to manually change each input data is a real torture.&lt;/p&gt;

&lt;p&gt;Here, after successfully calling the first API, I get an array of values. Now the need is to get a list of results by field code, then pass this array of results into the second API, and you can implement it. declared as follows&lt;/p&gt;

&lt;p&gt;Let’s say the JSON string below is the result of calling the API&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "data": [
        {
            "id": 1,
            "code": "org001",
            "name": "Organization A",
            "status": "ACTIVE"
        },
        {
            "id": 2,
            "code": "org002",
            "name": "Organization B",
            "status": "ACTIVE"
        },
        {
            "id": 3,
            "code": "org003",
            "name": "Organization C",
            "status": "INACTIVE"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also go to the tab Teststo write js script as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let responseData = pm.response.json().data; 
if (Array.isArray(responseData)) { 
  let codes = []; 
  responseData.forEach(item =&amp;gt; { 
    if (item &amp;amp;&amp;amp; item.hasOwnProperty("code")) { 
      codes.push(item.code); 
      } 
    }); 
  pm.globals.set("envSegments", JSON.stringify(codes)); 
  console.log("Size envSegments: "+codes.length); 
  console.log("envSegments: " + JSON.stringify(codes)); 
} else { 
console.log("Trường data không phải là một mảng"); 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5t3qn4kmdc6mjrmicch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5t3qn4kmdc6mjrmicch.png" width="754" height="376"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;script get list codes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And now in the API you need to use, you can take it out and use it similar to the above parts. Below is a sample request body snippet that I use. Please do not share the full request body but just stop at the part using variables. Okay, guys.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs96p92sf06k0xlr0mjjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs96p92sf06k0xlr0mjjf.png" width="602" height="119"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;using variable envSegments&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://dev.to/hungtvk12/tan-dung-script-trong-postman-de-tiet-kiem-thoi-gian-cua-ban-7pi-temp-slug-7225787"&gt;&lt;em&gt;https://cafeincode.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on March 24, 2024.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postmantesting</category>
      <category>postmanapi</category>
      <category>postman</category>
      <category>postmancollections</category>
    </item>
    <item>
      <title>Three threads execute sequentially, what implementations are there?</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Thu, 04 May 2023 10:53:14 +0000</pubDate>
      <link>https://dev.to/hungtvk12/three-threads-execute-sequentially-what-implementations-are-there-53lc</link>
      <guid>https://dev.to/hungtvk12/three-threads-execute-sequentially-what-implementations-are-there-53lc</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt3f5jqd7wwa952tzg73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt3f5jqd7wwa952tzg73.png" width="676" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today we will look a little bit at Java, for example, an interview question you are asked is as follows: the request requires three threads to execute sequentially, and what implementations are there to achieve it?&lt;/p&gt;

&lt;p&gt;The problem will be that we have three streams: Stream 1, Stream 2, and Stream 3, the requirement is that stream 1 will be processed first, then stream 2, and finally stream 3. We will have a few ways like after:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the Join method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Objects;

public class ThreadMain {

    public static void main(String[] args) {
        var t1 = new Thread(new Work(null));
        var t2 = new Thread(new Work(t1));
        var t3 = new Thread(new Work(t2));
        t1.start();
        t2.start();
        t3.start();
    }

    static class Work implements Runnable {
        private Thread beforeThread;

        public Work(Thread beforeThread) {
            this.beforeThread = beforeThread;
        }

        @Override
        public void run() {
            if (Objects.nonNull(beforeThread)) {
                try {
                    beforeThread.join();
                    System.out.println("Thread start : " + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Thread start : " + Thread.currentThread().getName());
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading the above code, you can understand some of the logic, passing parameters into the initialization function of streams 1, 2, and 3. At this time, it stream 1will be processed first, stream 2join stream 1will be processed further, and join stream 3with stream 2will be processed last.&lt;/p&gt;

&lt;p&gt;Start the application and see the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18jdkfnwln5e7wovpfqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18jdkfnwln5e7wovpfqw.png" width="732" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use CountDown Latch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.concurrent.CountDownLatch;

public class CountDownLatchMain {

    public static void main(String[] args) {
        var countDownLatchOne = new CountDownLatch(0);
        var countDownLatchTwo = new CountDownLatch(1);
        var countDownLatchThree = new CountDownLatch(1);

        var t1 = new Thread(new Work(countDownLatchOne, countDownLatchTwo));
        var t2 = new Thread(new Work(countDownLatchTwo, countDownLatchThree));
        var t3 = new Thread(new Work(countDownLatchThree, countDownLatchThree));

        t1.start();
        t2.start();
        t3.start();

    }

    static class Work implements Runnable {
        CountDownLatch cOne;
        CountDownLatch cTwo;

        public Work(CountDownLatch cOne, CountDownLatch cTwo) {
            this.cOne = cOne;
            this.cTwo = cTwo;
        }

        @Override
        public void run() {
            try {
                cOne.await();
                System.out.println("Thread using countdown latch start : " + Thread.currentThread().getName());
                cTwo.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, now start the application and see the results, then go into detail about its execution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkaqidglv7ns5a6awgvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkaqidglv7ns5a6awgvn.png" width="660" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the function main(), three objects CountDownLatchare created with initial values ​​of 0, 1, and 1.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;countDownLatchOneused to mark all threads as ready to start&lt;/li&gt;
&lt;li&gt;countDownLatchTwoused to start t2after t1having finished&lt;/li&gt;
&lt;li&gt;countDownLatchThreeused to start t3after t2having finished&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three objects are created with three corresponding Threadobjects passed in. WorkThen, three threads are started by calling the start().&lt;/p&gt;

&lt;p&gt;In class Work, the implementation is shown as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Class Workis an implementation class Runnablewhose purpose is to perform some work executed in a separate thread.&lt;/li&gt;
&lt;li&gt;The class Workhas two input parameters, which are two objects of the class CountDownLatch, cOneand cTwo.&lt;/li&gt;
&lt;li&gt;run()In the class method Work, before starting to execute work, the thread will call the await()above method cOne, waiting until cOnethe countdown value is reduced to 0.&lt;/li&gt;
&lt;li&gt;The thread will then print a message to confirm that it has started doing its work. This is the marker for t1completing your work.&lt;/li&gt;
&lt;li&gt;Finally, the thread will call the countDown()above method cTwoto decrement the countdown value of cTwoto 0. Decreasing the countdown value of cTwowill mark the t2start of execution.&lt;/li&gt;
&lt;li&gt;The same process will continue for t2and t3in the correct order of entry. That is, t2it will wait until cTwothe countdown value is reduced to 0 by calling the await()above method cTwo, then print a confirmation message and finally reduce the countdown value to 0 by calling the above cThreemethod.countDown()cThree&lt;/li&gt;
&lt;li&gt;Similarly, t3it will wait until cThreethe countdown value is reduced to zero by calling the await()above method cThree, printing a confirmation message, and finally ending its execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use ExecutorService
&lt;/h3&gt;

&lt;p&gt;We can implement a single thread group using ExecutorService but only use a single thread because if we deploy multiple thread groups, the order of T1, T2, and T3 will not be guaranteed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.concurrent.Executors;

public class ExecutorServiceMain {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -&amp;gt; System.out.println("Thread Start : " + Thread.currentThread().getName() + " 1"));

        Thread t2 = new Thread(() -&amp;gt; System.out.println("Thread Start : " + Thread.currentThread().getName() + " 2"));

        Thread t3 = new Thread(() -&amp;gt; System.out.println("Thread Start : " + Thread.currentThread().getName() + " 3"));

        var executor = Executors.newSingleThreadExecutor();
        executor.submit(t1);
        executor.submit(t2);
        executor.submit(t3);
        executor.shutdown();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s0h13myj5ch1mhz03xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s0h13myj5ch1mhz03xo.png" width="746" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above are a few ways to solve the problem of processing the order of streams. Good luck with your studies.&lt;/p&gt;

&lt;p&gt;Thanks, before you go:&lt;/p&gt;

&lt;p&gt;👏 Please clap for the story and follow the author 👉&lt;br&gt;&lt;br&gt;
Please share your questions or insights in the comments section below.&lt;br&gt;&lt;br&gt;
Let’s connect on &lt;a href="https://www.linkedin.com/in/hungtv27" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://dev.to/hungtvk12/ba-luong-thuc-hien-tuan-tu-co-nhung-cach-trien-khai-nao-3o3p-temp-slug-2121957"&gt;&lt;em&gt;https://cafeincode.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on May 4, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Kĩ năng quản lý căng thẳng cho Developer</title>
      <dc:creator>Hùng Trần</dc:creator>
      <pubDate>Sun, 02 Apr 2023 03:45:43 +0000</pubDate>
      <link>https://dev.to/hungtvk12/ki-nang-quan-ly-cang-thang-cho-developer-122e</link>
      <guid>https://dev.to/hungtvk12/ki-nang-quan-ly-cang-thang-cho-developer-122e</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nfoulkkn4diq2xbi1k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nfoulkkn4diq2xbi1k4.png" alt="Image description" width="676" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Khi là một Developer, bạn sẽ phải đối mặt với nhiều áp lực trong công việc, từ những deadline của dự án đến những vấn đề phức tạp trong mã nguồn. Điều này có thể khiến bạn cảm thấy căng thẳng và ảnh hưởng đến tinh thần, sức khỏe của mình.&lt;/p&gt;

&lt;p&gt;Vì vậy, việc quản lý căng thẳng là một kỹ năng cần thiết để giúp bạn duy trì sức khỏe tinh thần và hoàn thành công việc của mình một cách hiệu quả.&lt;/p&gt;

&lt;p&gt;Thời gian rất lâu trước đây mình cũng đã từng bị stress, căng thẳng tột độ cũng như trào ngược dạ dày cấp độ nặng, mà không chỉ là do công việc mà còn do ti tỉ thứ khác kết hợp lại dẫn đến.&lt;/p&gt;

&lt;p&gt;Trong bài viết hôm nay mình sẽ hướng dẫn các bạn một số tips có thể quản lý căng thẳng, giúp các bạn có một tâm trạng thoải mái hơn và đối diện được với những vấn đề trong công việc, cuộc sống.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tập trung vào giải pháp
&lt;/h3&gt;

&lt;p&gt;Tập trung vào giải pháp là một cách tiếp cận tích cực và hiệu quả để xử lý vấn đề. Thay vì tập trung vào những khó khăn và trở ngại, tập trung vào tìm ra giải pháp và cách thức để giải quyết vấn đề có thể giúp bạn giải quyết nhanh chóng và hiệu quả hơn.&lt;/p&gt;

&lt;p&gt;Tuy nhiên, việc tập trung vào giải pháp không có nghĩa là bạn không cần phải nhìn vào vấn đề. Điều quan trọng là bạn phải hiểu rõ và đánh giá chính xác tình hình để có thể đưa ra những giải pháp phù hợp. Bạn cần tìm hiểu và xác định nguyên nhân của vấn đề, đặt mục tiêu và lên kế hoạch để đạt được mục tiêu đó. Sau đó, hãy tập trung vào thực hiện giải pháp và theo dõi kết quả.&lt;/p&gt;

&lt;p&gt;Nhìn nhận tích cực và tập trung vào giải pháp có thể giúp bạn giải quyết vấn đề một cách nhanh chóng và hiệu quả hơn, đồng thời giúp cải thiện tinh thần và nâng cao năng lượng.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tìm kiếm hỗ trợ khi gặp khó khăn
&lt;/h3&gt;

&lt;p&gt;Nếu bạn gặp phải căng thẳng nghiêm trọng khi gặp phải việc khó hoặc không thể tự giải quyết được vấn đề, hãy nghĩ đến việc tìm kiếm sự giúp đỡ từ những đồng nghiệp nhiều kinh nghiệm hơn, để xem những góc nhìn mới từ họ như thế nào, từ đó có phương án để xử lý vấn đề cho bản thân.&lt;/p&gt;

&lt;p&gt;Hơn nữa việc tìm kiếm sự giúp đỡ từ người khác nó không đánh giá bạn là một người kém hiểu biết, mà ngược lại việc bạn tìm sự giúp đỡ từ đúng người nó còn chứng tỏ bạn là một người rất biết cách xử lý công việc, tối ưu hóa thời gian cá nhân.&lt;/p&gt;

&lt;h3&gt;
  
  
  Biết cách đặt giới hạn
&lt;/h3&gt;

&lt;p&gt;Phần này sẽ gồm hai ý:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Thứ nhất&lt;/code&gt;hãy học cách từ chối các yêu cầu không cần thiết hoặc nếu nhận lời thì thêm nó vào danh sách công việc của bạn và để làm sau, như kiểu nắm thông tin và đưa vào một danh sách công việc rồi dành thời gian xử lý sau nếu nó thực sự không gấp.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Thứ hai&lt;/code&gt;đó là hãy giảm kì vọng của bản thân xuống, đồng thời nâng mức độ chấp nhận của bản thân lên (Một quan điểm của &lt;code&gt;chủ nghĩa khắc kỉ&lt;/code&gt; giúp bản thân hạnh phúc hơn, mình sẽ nói ở một bài nào đó sau).&lt;/p&gt;

&lt;p&gt;Như kiểu các bạn kì vọng trong một ngày cần phải hoàn thành 10 công việc trong to-do list, nhưng đến cuối ngày nhìn lại chỉ hoàn thành được 7, 8 thôi chẳng hạn thì hãy chấp nhận nó và lấy đó làm mức tạm chấp nhận và cải thiện dần, nếu không các bạn sẽ rất dễ bị dính vào toxic-productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tjQqljmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tjQqljmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-4.png" width="778" height="434"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Toxic Productivity: ChatGPT said&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sắp xếp công việc hợp lý
&lt;/h3&gt;

&lt;p&gt;Đặt mục tiêu và lên kế hoạch để hoàn thành công việc một cách hợp lý và đều đặn. Bạn có thể sử dụng các công cụ quản lý thời gian như Asana hoặc Trello để giúp bạn tổ chức công việc của mình và đảm bảo rằng bạn hoàn thành công việc đúng hạn.&lt;/p&gt;

&lt;p&gt;Như cá nhân mình thì mình dùng Asana để quản lý công việc cá nhân, cũng như quản lý dự án ngoài, còn những dự án ở công ty thì dùng Jira.&lt;/p&gt;

&lt;p&gt;Mình lên kế hoạch công việc cho bản thân đều đặn theo tuần, theo ngày, và sau mỗi quý thì sẽ tổng hợp lại những thứ đã đạt được và so sánh với mục tiêu của bản thân từ đầu năm, sau đó điều chỉnh những quý tiếp theo cho phù hợp.&lt;/p&gt;

&lt;p&gt;Lời khuyên cá nhân là các bạn nên tập trung xử lý công việc vào đầu ngày, lúc đó chúng ta có thể giải quyết được rất nhiều thứ.&lt;/p&gt;

&lt;h3&gt;
  
  
  Duy trì việc tập thể dục
&lt;/h3&gt;

&lt;p&gt;Tập thể dục là một cách tuyệt vời để giảm stress và cải thiện sức khỏe tinh thần của bạn. Hãy dành thời gian để tập thể dục mỗi ngày và bạn sẽ cảm thấy ngày hôm đó cực kì nhiều năng lượng.&lt;/p&gt;

&lt;p&gt;Mình thấy nhiều người rất lạ, công việc bận thì họ ở lại công ty OT muộn (không nói đến những trường hợp golive hoặc xử lý gấp nên ở lại muộn vì nó có tính thời điểm) và đều lấy lý do là chưa giải quyết xong công việc và không dành được thời gian để thể dục thể thao.&lt;/p&gt;

&lt;p&gt;Mỗi tuần mình đều duy trì việc đi bộ buổi sáng hoặc đi bơi vào buổi tối, dù công việc bận bịu thế nào thì cũng luôn dành cho bản thân chút thời gian duy trì thể dục, mỗi ngày vận động một chút thì cơ thể sẽ cảm thấy thoải mái hơn và giảm căng thẳng rất tốt, hôm nào bận quá hoặc có việc riêng thì đành chịu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G8OQeSkg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-1024x677.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G8OQeSkg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-1024x677.png" width="800" height="529"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Bảng theo dõi tháng 01/2023&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Như tháng 1 thì cái tháng này là tháng có Tết nên mình chủ yếu đi bộ buổi sáng hoặc buổi chiều.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DQklbQyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DQklbQyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-1.png" width="800" height="561"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Bảng theo dõi tháng 02/2023&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sang tháng 2 thì có thêm đi bơi nhiều hơn.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7-NL37Xi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7-NL37Xi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-2.png" width="800" height="630"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Bảng theo dõi tháng 03/2023&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sang tháng 3 thì mình vẫn duy trì đi bộ/bơi, có nhiều hôm không hoàn thành được do là về quá muộn hoặc trời mưa nên Failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--djFpbjs3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/05/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--djFpbjs3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/05/image-1.png" width="800" height="610"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Bảng theo dõi tháng 04/2023&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tháng 4 bắt đầu hè về nên mình duy trì với tần suất cao hơn, các tháng tiếp theo mình sẽ update liên tục trong post này luôn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quản lý cảm xúc cá nhân
&lt;/h3&gt;

&lt;p&gt;Học cách quản lý cảm xúc của mình là một kỹ năng quan trọng trong việc quản lý căng thẳng. Hãy tìm hiểu cách quản lý cảm xúc của mình và biết cách kiểm soát chúng để không bị tác động tiêu cực, lắng nghe người khác nhiều hơn và đưa ra phản hồi một cách hợp lý.&lt;/p&gt;

&lt;p&gt;Hãy học cách &lt;a href="https://cafeincode.com/ban-khong-gioi-lang-nghe-nhu-ban-nghi-dau/" rel="noopener noreferrer"&gt;lắng nghe tích cực&lt;/a&gt; từ bài trước của mình để có thêm những góc nhìn mới và có thể hiểu người khác hơn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Học cách thở dài sinh lý
&lt;/h3&gt;

&lt;p&gt;Khi chúng ta cảm thấy căng thẳng thì nhịp tim thường rơi vào trạng thái đập điên loạn và cường độ cao, lúc này có một cách giúp bạn có thể đưa nhịp tim trở về trạng thái ổn định ngay lập tức đó là &lt;code&gt;Thở Dài Sinh Lý&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hdE1S6y0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hdE1S6y0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cafeincode.com/wp-content/uploads/2023/04/image-5.png" width="784" height="468"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Thở dài sinh lý 2 lần hít vào 1 lần thở ra sâu (ChatGPT said)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Kĩ thuật này mình học được từ một bác Giáo Sư trong lĩnh vực thần kinh học của Mỹ, và khi áp dụng vào công việc hằng ngày thì mình thấy nó thực sự hiệu quả.&lt;/p&gt;

&lt;p&gt;Có nhiều lần đồng nghiệp ngồi cạnh thấy mình thở dài thì đều hỏi tại sao lại thở dài, chán chường điều gì hay sao? và mình có giải thích đó là một cách điều hòa nhịp tim, tăng cường tập trung và giảm mệt mỏi chứ không phải là một trạng thái chán chường thông thường bằng thở dài.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dành thời gian nghỉ ngơi, gặp gỡ bạn bè
&lt;/h3&gt;

&lt;p&gt;Một trong những cách giảm căng thẳng cơ bản đó là social-network, hiểu một cách đơn giản đó là dành thời gian cho việc gặp gỡ bạn bè, người thân, những người mà chúng ta cảm thấy thực sự tin tưởng.&lt;/p&gt;

&lt;p&gt;Đó là một cách rất hữu hiệu để tăng hormone serotonin trong cơ thể, giúp tâm trạng của bạn trở nên thoải mái và hạnh phúc hơn. Khi đang nghỉ ngơi thì hãy cố gắng gạt công việc sang một bên, tạm thời không cần nghĩ đến nó nữa sẽ khiến cơ thể rất thoải mái.&lt;/p&gt;

&lt;h3&gt;
  
  
  Học cách điều chỉnh quan điểm
&lt;/h3&gt;

&lt;p&gt;Cố gắng nhìn nhận vấn đề một cách tích cực và tìm cách giải quyết nó. Mỗi người sẽ có một quan điểm cá nhân khác nhau, quan điểm tốt và tích cực thì chúng ta học hỏi, quan điểm sai trái thì nhìn nhận và loại trừ, nó sẽ giúp cá nhân bạn tạo ra một trải nghiệm tích cực trong công việc cũng như trong cuộc sống.&lt;/p&gt;

&lt;p&gt;Với những kỹ năng quản lý căng thẳng này, bạn có thể duy trì sức khỏe tinh thần và hoàn thành công việc của mình một cách hiệu quả. Điều quan trọng là bạn phải luôn chú ý đến sức khỏe của mình và biết cách giải quyết căng thẳng để không bị tác động đến tâm trí và sức khỏe của mình. Chúc bạn thành công trong công việc và cuộc sống!&lt;/p&gt;

</description>
      <category>share</category>
      <category>softskill</category>
      <category>tâmsự</category>
      <category>worklifebalance</category>
    </item>
  </channel>
</rss>
