Apache foundation provides an HttpClient library which is used for sending http requests from java program.
Sending GET and POST requests with HttpClient library is pretty easy.
This article will explain how to use HttpClient to send http requests as rest calls from java with examples.

Adding HttpClient
For using HttpClient library, first you need to add it to your project.
You can directly download its jar and add it to classpath or if you are using a build tool, then add its dependency as below.

Maven

<dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.13</version>
    </dependency>

Gradle

compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13'

Following are the steps required for using Apache HttpClient to send requests and receive response.
If you are not interested in the explanation, then directly jump to the example below.

1. Creating HttpClient
In order to execute HTTP requests with HttpClient, first we need to create a client object which can send requests to a remote URL.
In Apache HttpClient, this is done using createDefault() method of org.apache.http.impl.client.HttpClients class. This is a static method and returns an instance of CloseableHttpClient.

CloseableHttpClient httpClient = HttpClients.createDefault();

Many examples in other tutorials are using DefaultHttpClient to create a client object

DefaultHttpClient c = new DefaultHttpClient();

This method is now deprecated and should not be used.

2. Creating request
Second step is to create a request object. This actually also shows the type of request.
Apache HttpClient has different classes for each of request types such as HttpGet for GET, HttpPost for POST, HttpDelete for DELETE and so on.
All these objects accept a string URL to which the request should be sent. Example,

HttpGet get = new HttpGet("http://google.com");

3. Sending request
CloseableHttpClient has an execute() method which accepts a request object that we created in the last section.
Simply provide the request object and it will send it to the desired URL as shown below.

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet get = new HttpGet(<URL>);
httpClient.execute(get);

4. Reading response
execute() method returns an object of type CloseableHttpResponse. This is a marker interface.
Its implementing class contains returned response but in object format which needs to be converted to a string to be utilized.
There are two ways to convert response object to a string.
A. Reading Inputstream
Object of type CloseableHttpResponse provides a method getEntity(), which in turn provides a method getContent() returning an inputstream containing the response.
This inputstream can be converted to a string. Example,

CloseableHttpResponse response = closeableHttpClient.execute(get);
InputStream inputStream = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new java.io.InputStreamReader(inputStream));
String responseStr = null;
while((responseStr = reader.readLine())!=null) {
   System.out.println(responseStr);
}

B. Using EntityUtils
Object of type CloseableHttpResponse provides a method getEntity(), which is an object of type HttpEntity.
This can be directly converted to a string using org.apache.http.util.EntityUtils class as shown below.

CloseableHttpResponse response = closeableHttpClient.execute(get);
HttpEntity entity = response.getEntity();
String responseStr = EntityUtils.toString(entity);

or in one-liner

CloseableHttpResponse response = closeableHttpClient.execute(get); 
String responseStr = EntityUtils.toString(
                       response.getEntity()
                     );

HttpClient GET example
Putting all the above steps together, we are ready to execute a GET request with Apache HttpClient.
Complete example follows.

// create client
CloseableHttpClient client = HttpClients.createDefault();
// create request object
HttpGet get = new HttpGet("http://dummy.restapiexample.com/api/v1/employee/1");
BufferedReader reader = null;
try {
  // send request
  CloseableHttpResponse response = client.execute(get);
  // read response
  InputStream inputStream = response.getEntity().getContent();
  reader = new BufferedReader(new java.io.InputStreamReader(inputStream));
  String line = null;
  while((line = reader.readLine())!=null) {
    System.out.println(line);
  }
} catch (ClientProtocolException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
} finally {
   if(reader != null) {
     reader.close();
   }
   if(client != null) {
     client.close();
   }
}

This example uses a Fake REST API. The response returned is printed below.

{
"status":"success",
"data":{
  "id":1,
  "employee_name":"Tiger Nixon",
  "employee_salary":320800,
  "employee_age":61,
  "profile_image":""
},
"message":"Successfully! Record has been fetched."
}

Getting Response code
You can also retrieve other details from the response such as the response code, protocol from the response object as shown below.

CloseableHttpResponse response = client.execute(get);
System.out.println(response.getStatusLine().getStatusCode());
System.out.println(response.getProtocolVersion());
System.out.println(response.getStatusLine());

which prints

200
HTTP/1.1
HTTP/1.1 200 OK

Getting response headers
Response object has a getHeaders() method which returns an array of Header objects.
This array can be iterated to get the header information. Example,

CloseableHttpResponse response = closeableHttpClient.execute(get);
Header[] allHeaders = response.getAllHeaders();
for (Header header : allHeaders) {
  System.out.println("Header: "+header.getName()+ ", Value: "+header.getValue());
}

Note that the array is iterated using an enhanced for loop in java.
This prints

Header: Cache-Control, Value: no-cache, private, max-age=31536000
Header: Content-Type, Value: application/json
Header: Date, Value: Tue, 13 Oct 2020 06:31:25 GMT
Header: Display, Value: staticcontent_sol
Header: Expires, Value: Wed, 13 Oct 2021 06:31:24 GMT
Header: Host-Header, Value: c2hhcmVkLmJsdWVob3N0LmNvbQ==
Header: Referrer-Policy, Value:
Header: Response, Value: 200
// other headers truncated

If you want to retrieve a header value from its name, then you can also use getFirstHeader(), getLastHeader() and getHeaders() methods supplying the header name as argument.

HttpClient POST example
Sending a POST request with HttpClient also involves the same steps but with a few modifications.
1. You need to create an object of HttpPost that represents the request.
2. If there are some parameters that need to be sent as the body of the request, then those also need to be set.

Example follows

// create client
CloseableHttpClient client = HttpClients.createDefault();
// create request object
HttpPost post = new HttpPost("https://jsonplaceholder.typicode.com/posts");
try {
  List params = new ArrayList<>();
  params.add(new BasicNameValuePair("userId", "1"));
  params.add(new BasicNameValuePair("title", "Dummy title"));
  params.add(new BasicNameValuePair("body", "Dummy body"));
  post.setEntity(new UrlEncodedFormEntity(params));
  // send request
  CloseableHttpResponse response = client.execute(post);
  // read response			
  String responseStr = EntityUtils.toString(response.getEntity());
  System.out.println(responseStr);
} catch (ClientProtocolException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
} finally {
   if(client != null) {
     client.close();
   }
}

Parameters that need to be sent as a part of request body are sent in the form of name-value pairs.

For creating a name-value pair, create an object of type BasicNameValuePair using its constructor that takes name and value as arguments.
Add all the name-value pairs to a List and add this list to request object using its setEntity() method.
POST request is then sent using execute() method of CloseableHttpClient.

Below is the response

{
“userId”: “1”,
“title”: “Dummy title”,
“body”: “Dummy body”,
“id”: 101
}

This shows that a record with id 101 was created on the server.
HttpClient POST JSON example
You might want to send JSON data to the REST end point since it might be a Spring controller which is expecting a java object.
With HttpClient, you can send a JSON string as shown below.

// create client
CloseableHttpClient client = HttpClients.createDefault();
// create request object
HttpPost post = new HttpPost("https://jsonplaceholder.typicode.com/posts");
try {
  String json = "{\"userId\":1,\"body\":\"Dummy\"}";
  StringEntity entity = new StringEntity(json);
  post.setEntity(new UrlEncodedFormEntity(params));
  // send request
  CloseableHttpResponse response = client.execute(post);
  // read response			
  String responseStr = EntityUtils.toString(response.getEntity());
  System.out.println(responseStr);
} catch (ClientProtocolException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
} finally {
   if(client != null) {
     client.close();
   }
}

Only difference is that you need to create an object of StringEntity supplying it the JSON string.
This entity can then be set into request object using setEntity() method just like we did in earlier example.
Sending object in POST
You might have a java object that you want to send as POST request body.
This object needs to be converted to a JSON String and then it can be sent in the same way as shown in last example.
Jackson’s ObjectMapper can be used to convert an object to a JSON string as shown below.

HttpPost post = new HttpPost("https://jsonplaceholder.typicode.com/posts");
// create object to send in body
Post postObj = new Post();
// set values
postObj.setBody("Dummy body");
postObj.setUserId(1);
postObj.setTitle("Dummy Title");
// convert it to JSON string
ObjectMapper mapper = new ObjectMapper();
String objectStr = mapper.writeValueAsString(postObj);
StringEntity entity = new StringEntity(objectStr);
// set it in request
post.setEntity(entity);

You can also convert an object to a JSON string by appending its properties and values together in a valid JSON format.
But this approach is not recommended for larger objects since it would require multiple string operations and it is error prone.
Hope the article was helpful.