Java Top Codes
Java Fibonacci Series Program: Loop, Recursion and Memoization
The Fibonacci series starts with 0, 1 and every next number is the sum of the two before it: 0, 1, 1, 2, 3, 5, 8, 13... Here are three ways to write it in Java.
1. Using a loop (the best way)
public class Main {
public static void main(String[] args) {
int count = 12;
long a = 0, b = 1;
for (int i = 0; i < count; i++) {
System.out.print(a + " ");
long next = a + b;
a = b;
b = next;
}
System.out.println();
}
}
0 1 1 2 3 5 8 13 21 34 55 89
2. Using recursion
public class Rec {
static int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
for (int i = 0; i < 12; i++) {
System.out.print(fib(i) + " ");
}
System.out.println();
}
}
0 1 1 2 3 5 8 13 21 34 55 89
This is simple, but it calculates the same values again and again. It becomes very slow for numbers like fib(45).
3. Recursion with memoization
We save each answer in a map, so it is calculated only once.
import java.util.HashMap;
import java.util.Map;
public class Memo {
static Map<Integer, Long> cache = new HashMap<>();
static long fib(int n) {
if (n <= 1) return n;
if (cache.containsKey(n)) return cache.get(n);
long value = fib(n - 1) + fib(n - 2);
cache.put(n, value);
return value;
}
public static void main(String[] args) {
System.out.println(fib(10));
System.out.println(fib(50));
System.out.println(fib(90)); // the biggest one which fits in a long is fib(92)
}
}
55
12586269025
2880067194370816120
Which one to use?
| Way | Speed | Note |
|---|---|---|
| Loop | Very fast | Simple and uses no extra memory |
| Plain recursion | Very slow for big n | Good only to learn recursion |
| Memoization | Fast | Uses memory for the cache, and deep recursion for a big n |
Related: Java Recursion and Java HashMap.
Java Factorial Program with Loop, Recursion and BigInteger
The factorial of n is n x (n-1) x ... x 1, for example 5! = 120. It grows very fast: 21! is already too big for a long.
Loop and recursion
public class Main {
static long factorialLoop(int n) {
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
static long factorialRec(int n) {
return n <= 1 ? 1 : n * factorialRec(n - 1);
}
public static void main(String[] args) {
System.out.println(factorialLoop(5));
System.out.println(factorialRec(10));
System.out.println(factorialLoop(20)); // the biggest one for a long
System.out.println(factorialLoop(21)); // overflow: wrong value, no error
}
}
120
3628800
2432902008176640000
-4249290049419214848
BigInteger for big results
import java.math.BigInteger;
public class Big {
static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
public static void main(String[] args) {
System.out.println(factorial(21));
System.out.println(factorial(30));
BigInteger f100 = factorial(100);
System.out.println(f100.toString().length() + " digits");
System.out.println(f100.toString().substring(0, 20) + "...");
}
}
51090942171709440000
265252859812191058636308480000000
158 digits
93326215443944152681…
BigInteger has no size limit. It is slower than long, so use it only when you need it.
Check the negative input
public class Neg {
static long factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException("Factorial is not defined for negative numbers: " + n);
}
return n <= 1 ? 1 : n * factorial(n - 1);
}
public static void main(String[] args) {
System.out.println(factorial(-3));
}
}
Exception in thread "main" java.lang.IllegalArgumentException: Factorial is not defined for negative numbers: -3
at Neg.factorial(Neg.java:4)
at Neg.main(Neg.java:10)
Related: Java Recursion and Java Exceptions.
Java Armstrong Number Program
An Armstrong number (narcissistic number) is a number which is equal to the sum of its digits, each raised to the power of the number of digits. For example 153 = 1^3 + 5^3 + 3^3.
Program
public class Main {
static boolean isArmstrong(int number) {
int digits = String.valueOf(number).length();
int sum = 0;
int n = number;
while (n > 0) {
int digit = n % 10;
sum += (int) Math.pow(digit, digits);
n /= 10;
}
return sum == number;
}
public static void main(String[] args) {
System.out.println(isArmstrong(153));
System.out.println(isArmstrong(154));
System.out.println(isArmstrong(9474));
System.out.print("Armstrong numbers up to 1000: ");
for (int i = 1; i <= 1000; i++) {
if (isArmstrong(i)) {
System.out.print(i + " ");
}
}
System.out.println();
}
}
true
false
true
Armstrong numbers up to 1000: 1 2 3 4 5 6 7 8 9 153 370 371 407
How it works
String.valueOf(number).length()counts the digits.- The loop takes the last digit with
% 10, raises it to the power of the digit count, and adds it. - Every single digit number (1 to 9) is an Armstrong number, because
d^1 = d.
Related: Java while Loop and Java Math Class.
Java Program to Read a CSV File and Calculate the Total
CSV files are everywhere. This program reads a small sales file, skips the header, ignores bad lines, and shows the total and the average.
Program
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class Main {
record Sale(String item, int quantity, double price) {
double amount() { return quantity * price; }
}
public static void main(String[] args) throws IOException {
Path file = Path.of("sales.csv");
Files.write(file, List.of(
"item,quantity,price",
"Pen,10,5.50",
"Book,2,250",
"Bag,1,899.99",
"Broken line",
"Notebook,abc,40"));
List<Sale> sales = Files.readAllLines(file).stream()
.skip(1) // header
.map(Main::parse)
.filter(s -> s != null)
.toList();
double total = sales.stream().mapToDouble(Sale::amount).sum();
System.out.println("Valid rows: " + sales.size());
sales.forEach(s -> System.out.printf("%-10s %8.2f%n", s.item(), s.amount()));
System.out.printf("Total: %.2f%n", total);
System.out.printf("Average per row: %.2f%n", total / sales.size());
}
static Sale parse(String line) {
String[] p = line.split(",");
if (p.length != 3) {
System.out.println("Skipped (wrong columns): " + line);
return null;
}
try {
return new Sale(p[0].trim(), Integer.parseInt(p[1].trim()), Double.parseDouble(p[2].trim()));
} catch (NumberFormatException e) {
System.out.println("Skipped (bad number): " + line);
return null;
}
}
}
Skipped (wrong columns): Broken line
Skipped (bad number): Notebook,abc,40
Valid rows: 3
Pen 55.00
Book 500.00
Bag 899.99
Total: 1454.99
Average per row: 485.00
Notes
split(",")is fine for simple files. If a value can contain a comma inside quotes, use a CSV library such as Apache Commons CSV.- We use a
recordfor a row, and a stream to process the lines. See Java Records and Java Streams. - For huge files, use
Files.lines()in a try with resources and process one line at a time. See Java File Handling.
Java HttpClient Example: GET and POST Requests
Since Java 11 the standard library has a modern HTTP client: java.net.http.HttpClient. The example below starts a very small web server in the same program (with com.sun.net.httpserver), so it runs without internet, and then calls it with GET and POST.
Program
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
// A tiny server for the test
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
server.createContext("/hello", exchange -> {
byte[] body = "{\"message\":\"Hello from the server\"}".getBytes(StandardCharsets.UTF_8);
exchange.getResponseHeaders().add("Content-Type", "application/json");
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.close();
});
server.createContext("/echo", exchange -> {
String text = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
byte[] body = ("You sent: " + text).getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(201, body.length);
exchange.getResponseBody().write(body);
exchange.close();
});
server.start();
int port = server.getAddress().getPort();
// The client
HttpClient client = HttpClient.newHttpClient();
HttpRequest get = HttpRequest.newBuilder(URI.create("http://127.0.0.1:" + port + "/hello"))
.GET()
.build();
HttpResponse<String> r1 = client.send(get, HttpResponse.BodyHandlers.ofString());
System.out.println("GET status: " + r1.statusCode());
System.out.println("Content-Type: " + r1.headers().firstValue("Content-Type").orElse("?"));
System.out.println("Body: " + r1.body());
HttpRequest post = HttpRequest.newBuilder(URI.create("http://127.0.0.1:" + port + "/echo"))
.header("Content-Type", "text/plain")
.POST(HttpRequest.BodyPublishers.ofString("name=Riya"))
.build();
HttpResponse<String> r2 = client.send(post, HttpResponse.BodyHandlers.ofString());
System.out.println("POST status: " + r2.statusCode());
System.out.println("Body: " + r2.body());
server.stop(0);
}
}
GET status: 200
Content-Type: application/json
Body: {"message":"Hello from the server"}
POST status: 201
Body: You sent: name=Riya
Use it with a real API
Change the address to a real one, like https://api.example.com/items. The code is the same. Always set a timeout and check the status code:
HttpClient client = HttpClient.newBuilder()
.connectTimeout(java.time.Duration.ofSeconds(5))
.build();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.example.com/items"))
.timeout(java.time.Duration.ofSeconds(10))
.header("Accept", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
System.out.println(response.body());
}
client.send()waits for the answer.client.sendAsync()returns aCompletableFuture.- The JSON text must be read with a library like Jackson or Gson. The JDK has no JSON parser.
Java Random Password Generator with SecureRandom
For passwords never use Math.random() or Random, because their numbers can be predicted. Use SecureRandom, which is made for security. This generator makes sure that the password has at least one character of each type.
Program
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
static final String UPPER = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // no I and O: easy to confuse
static final String LOWER = "abcdefghijkmnopqrstuvwxyz"; // no l
static final String DIGITS = "23456789"; // no 0 and 1
static final String SYMBOLS = "!@#$%^&*-_=+";
static final SecureRandom RANDOM = new SecureRandom();
static String generate(int length) {
if (length < 8) {
throw new IllegalArgumentException("Use at least 8 characters");
}
String all = UPPER + LOWER + DIGITS + SYMBOLS;
List<Character> chars = new ArrayList<>();
chars.add(pick(UPPER)); // one of each type
chars.add(pick(LOWER));
chars.add(pick(DIGITS));
chars.add(pick(SYMBOLS));
while (chars.size() < length) {
chars.add(pick(all));
}
Collections.shuffle(chars, RANDOM);
StringBuilder sb = new StringBuilder();
for (char c : chars) sb.append(c);
return sb.toString();
}
static char pick(String set) {
return set.charAt(RANDOM.nextInt(set.length()));
}
public static void main(String[] args) {
String password = generate(14);
System.out.println("Length: " + password.length());
System.out.println("Has upper: " + password.chars().anyMatch(Character::isUpperCase));
System.out.println("Has lower: " + password.chars().anyMatch(Character::isLowerCase));
System.out.println("Has digit: " + password.chars().anyMatch(Character::isDigit));
System.out.println("Has symbol: " + password.chars().anyMatch(c -> SYMBOLS.indexOf(c) >= 0));
System.out.println("Two passwords are different: " + !generate(14).equals(generate(14)));
}
}
Length: 14
Has upper: true
Has lower: true
Has digit: true
Has symbol: true
Two passwords are different: true
We print the checks and not the password itself, because a real password is different on every run. When you run it, print password to see it.
Good to know
SecureRandomuses the random source of the operating system.- Removing the letters which look alike (
l,1,O,0) makes a password easier to read. - Never save a password as plain text. Save a hash made with a slow algorithm like bcrypt, scrypt or Argon2.
- Never write passwords in logs or in the source code.
Related: Java Math Class and Java Strings.