воскресенье, 12 мая 2024 г.

Stream in Java

    Java Streams is a powerful feature introduced in Java 8 that simplifies the processing of collections and sequences of data. Streams enable you to perform complex operations on data with concise and expressive code.

Stream is a sequence of data that you can process in a declarative and functional style. It allows you to perform operations such as filtering, mapping, and reducing on a collection of data. Streams can be used with various data sources, including arrays, collections, and even I/O channels.

Arrays: You can create a stream from an array using the Arrays.stream() method.
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> nameStream = names.stream();

- Collections: Java collections such as lists, sets, and maps can be converted to streams using the stream() method.
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> nameStream = names.stream();

- I/O Channels: Java provides classes like BufferedReader for reading from input sources like files. These classes can be wrapped into streams using methods like lines().
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
// Process the lines in the file
} catch (IOException e) {
e.printStackTrace();
}

- Stream.of() is a static factory method in Java's Stream class that allows you to create a stream from a sequence of elements.
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);

Once you have a Stream, you can perform various operations on it. Stream operations can be categorized into two types: intermediate and terminal operations.

Intermediate operations transform the elements of the stream and produce a new stream as a result. Some common intermediate operations in Java streams include filter, map, flatMap, distinct, sorted, limit, and skip, among others.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "banana");

// Filter words starting with 'a'
List<String> filteredWords = words.stream()
.filter(word -> word.startsWith("a"))
.collect(Collectors.toList());
System.out.println("Words starting with 'a': " + filteredWords);

// Map each word to its length
List<Integer> wordLengths = words.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println("Word lengths: " + wordLengths);

// Remove duplicates
List<String> distinctWords = words.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("Distinct words: " + distinctWords);

// Sort words alphabetically
List<String> sortedWords = words.stream()
.sorted()
.collect(Collectors.toList());
System.out.println("Sorted words: " + sortedWords);

// Limit to first 3 words
List<String> firstThreeWords = words.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println("First three words: " + firstThreeWords);

// Skip first 2 words
List<String> skippedFirstTwoWords = words.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println("Skipped first two words: " + skippedFirstTwoWords);
}
}

Words starting with 'a': [apple]
Word lengths: [5, 6, 6, 5, 6]
Distinct words: [apple, banana, orange, grape]
Sorted words: [apple, banana, banana, grape, orange]
First three words: [apple, banana, orange]
Skipped first two words: [orange, grape, banana]


Terminal operations in Java streams are the final operations that produce a result or a side-effect. Once a terminal operation is applied to a stream, it consumes the stream and produces a result, such as a list, a value, or even performing an action like printing elements.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Main {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "banana");

// forEach terminal operation
System.out.println("Printing each word:");
words.stream().forEach(System.out::println);

// count terminal operation
long wordCount = words.stream().count();
System.out.println("Total words count: " + wordCount);

// min/max terminal operation
Optional<String> minWord = words.stream().min(String::compareToIgnoreCase);
minWord.ifPresent(min -> System.out.println("Minimum word: " + min));

// findFirst terminal operation
Optional<String> firstWord = words.stream().findFirst();
firstWord.ifPresent(first -> System.out.println("First word: " + first));

// anyMatch terminal operation
boolean hasApple = words.stream().anyMatch(word -> word.equals("apple"));
System.out.println("Does the list contain 'apple'? " + hasApple);

// allMatch terminal operation
boolean allHaveLengthGreaterThanTwo = words.stream().allMatch(word -> word.length() > 2);
System.out.println("Do all words have length greater than 2? " + allHaveLengthGreaterThanTwo);

// noneMatch terminal operation
boolean noneHaveLengthGreaterThanTen = words.stream().noneMatch(word -> word.length() > 10);
System.out.println("Do none of the words have length greater than 10? " + noneHaveLengthGreaterThanTen);

// collect terminal operation toList
List<String> collectedList = words.stream().filter(word -> word.length() > 5).collect(Collectors.toList());
System.out.println("Words with length greater than 5: " + collectedList);

// reduce terminal operation
Optional<String> concatenatedWords = words.stream().reduce((word1, word2) -> word1 + ", " + word2);
concatenatedWords.ifPresent(concatenated -> System.out.println("Concatenated words: " + concatenated));

// toArray terminal operation
Object[] wordsArray = words.stream().toArray();
System.out.println("Words as array: " + Arrays.toString(wordsArray));
}
}

Printing each word:
apple
banana
orange
grape
banana
Total words count: 5
Minimum word: apple
First word: apple
Does the list contain 'apple'? true
Do all words have length greater than 2? true
Do none of the words have length greater than 10? true
Words with length greater than 5: [orange, banana]
Concatenated words: apple, banana, orange, grape, banana
Words as array: [apple, banana, orange, grape, banana]

среда, 8 мая 2024 г.

Lambda Expressions in Java

    Lambda expression is a new and important feature of Java which was included in Java SE 8. It provides a clear and concise way to represent one method interface using an expression. It is very useful in collection library. It helps to iterate, filter and extract data from collection.

The Lambda expression is used to provide the implementation of an interface which has functional interface. It saves a lot of code. In case of lambda expression, we don't need to define the method again for providing the implementation. Here, we just write the implementation code.

(argument-list) -> {body}  

Java lambda expression is consisted of three components.

1) Argument-list: It can be empty or non-empty as well.

2) Arrow-token: It is used to link arguments-list and body of expression.

3) Body: It contains expressions and statements for lambda expression.


Without Lambda Expression

interface Drawable{
public void draw();
}
public class LambdaExpressionExample {
public static void main(String[] args) {
int width=10;
//without lambda, Drawable implementation using anonymous class
Drawable d=new Drawable(){
public void draw(){System.out.println("Drawing "+width);}
};
d.draw();
}
}

Lambda Expression Example

@FunctionalInterface //It is optional
interface Drawable{
public void draw();
}
public class LambdaExpressionExample2 {
public static void main(String[] args) {
int width=10;
//with lambda
Drawable d2=()->{
System.out.println("Drawing "+width);
};
d2.draw();
}
}

If there is only one statement, you may or may not use return keyword. You must use return keyword when lambda expression contains multiple statements.
interface Addable{
int add(int a,int b);
}
public class LambdaExpressionExample6 {
public static void main(String[] args) {
// Lambda expression without return keyword.
Addable ad1=(a,b)->(a+b);
System.out.println(ad1.add(10,20));
// Lambda expression with return keyword.
Addable ad2=(int a,int b)->{
return (a+b);
};
System.out.println(ad2.add(100,200));
}
}

Functional Interfaces in Java

    An Interface that contains exactly one abstract method is known as functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of object class.

@FunctionalInterface
interface sayable{
void say(String msg); // abstract method
// It can contain any number of Object class methods.
int hashCode();
String toString();
boolean equals(Object obj);
}
public class FunctionalInterfaceExample2 implements sayable{
public void say(String msg){
System.out.println(msg);
}
public static void main(String[] args) {
FunctionalInterfaceExample2 fie = new FunctionalInterfaceExample2();
fie.say("Hello there");
}
}

Java provides predefined functional interfaces to deal with functional programming by using lambda and method references.

InterfaceDescription
BiConsumer<T,U>It represents an operation that accepts two input arguments and returns no result.
Consumer<T>It represents an operation that accepts a single argument and returns no result.
Function<T,R>It represents a function that accepts one argument and returns a result.
Predicate<T>It represents a predicate (boolean-valued function) of one argument.
BiFunction<T,U,R>It represents a function that accepts two arguments and returns a a result.
BinaryOperator<T>It represents an operation upon two operands of the same data type. It returns a result of the same type as the operands.
BiPredicate<T,U>It represents a predicate (boolean-valued function) of two arguments.
BooleanSupplierIt represents a supplier of boolean-valued results.
DoubleBinaryOperatorIt represents an operation upon two double type operands and returns a double type value.
DoubleConsumerIt represents an operation that accepts a single double type argument and returns no result.
DoubleFunction<R>It represents a function that accepts a double type argument and produces a result.
DoublePredicateIt represents a predicate (boolean-valued function) of one double type argument.
DoubleSupplierIt represents a supplier of double type results.
DoubleToIntFunctionIt represents a function that accepts a double type argument and produces an int type result.
DoubleToLongFunctionIt represents a function that accepts a double type argument and produces a long type result.
DoubleUnaryOperatorIt represents an operation on a single double type operand that produces a double type result.
IntBinaryOperatorIt represents an operation upon two int type operands and returns an int type result.
IntConsumerIt represents an operation that accepts a single integer argument and returns no result.
IntFunction<R>It represents a function that accepts an integer argument and returns a result.
IntPredicateIt represents a predicate (boolean-valued function) of one integer argument.
IntSupplierIt represents a supplier of integer type.
IntToDoubleFunctionIt represents a function that accepts an integer argument and returns a double.
IntToLongFunctionIt represents a function that accepts an integer argument and returns a long.
IntUnaryOperatorIt represents an operation on a single integer operand that produces an integer result.
LongBinaryOperatorIt represents an operation upon two long type operands and returns a long type result.
LongConsumerIt represents an operation that accepts a single long type argument and returns no result.
LongFunction<R>It represents a function that accepts a long type argument and returns a result.
LongPredicateIt represents a predicate (boolean-valued function) of one long type argument.
LongSupplierIt represents a supplier of long type results.
LongToDoubleFunctionIt represents a function that accepts a long type argument and returns a result of double type.
LongToIntFunctionIt represents a function that accepts a long type argument and returns an integer result.
LongUnaryOperatorIt represents an operation on a single long type operand that returns a long type result.
ObjDoubleConsumer<T>It represents an operation that accepts an object and a double argument, and returns no result.
ObjIntConsumer<T>It represents an operation that accepts an object and an integer argument. It does not return result.
ObjLongConsumer<T>It represents an operation that accepts an object and a long argument, it returns no result.
Supplier<T>It represents a supplier of results.
ToDoubleBiFunction<T,U>It represents a function that accepts two arguments and produces a double type result.
ToDoubleFunction<T>It represents a function that returns a double type result.
ToIntBiFunction<T,U>It represents a function that accepts two arguments and returns an integer.
ToIntFunction<T>It represents a function that returns an integer.
ToLongBiFunction<T,U>It represents a function that accepts two arguments and returns a result of long type.
ToLongFunction<T>It represents a function that returns a result of long type.
UnaryOperator<T>It represents an operation on a single operand that returnsa a result of the same type as its operand.


четверг, 2 мая 2024 г.

Optional class in Java

    Optional class is a public final class and used to deal with NullPointerException in Java application. You must import java.util package to use this class. It provides methods which are used to check the presence of value for particular variable.

import java.util.Optional;

public class OptionalExample {
public static void main(String[] args) {
Optional<String> optionalName = Optional.of("John");

// Check if a value is present
if (optionalName.isPresent()) {
System.out.println("Name is present: " + optionalName.get());
}

// Providing a default value if the optional is empty
String name = optionalName.orElse("Default Name");
System.out.println("Name or default: " + name);

// Handling the case when a value is absent
Optional<String> emptyOptional = Optional.empty();
String defaultName = emptyOptional.orElse("Default Name");
System.out.println("Default name from empty optional: " + defaultName);

// Throwing an exception if a value is absent
try {
String nameOrThrow = emptyOptional.orElseThrow(IllegalStateException::new);
System.out.println("Name or throw: " + nameOrThrow);
} catch (IllegalStateException e) {
System.out.println("Caught IllegalStateException: " + e.getMessage());
}
}
}