Setter Dependency Injection in Spring

In the post dependency injection in Spring we have already gone through the concept of dependency injection, in this post we’ll see in details one of the type of dependency injection- Setter dependency injection in Spring.

For another type of dependency injection, Constructor dependency injection check this post- Constructor Dependency Injection in Spring

Spring Setter dependency injection

In setter based DI Spring container calls setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean.

For configuring setter based dependencies you can use XML configuration as well as annotations. We’ll see examples of doing it using both of these ways.

Spring Setter dependency injection Example

In the example there is a class to place orders called Order and purchase can be done from an online store or a retail store. In Order class dependencies for the properties are injected using setter dependency injection.

public interface IStore {
  public void doPurchase(int items);
}
public class OnlineStore implements IStore {
  public void doPurchase(int items) {
    System.out.println("Doing online purchase of " + items + " Items");
  }
}
public class RetailStore implements IStore {
  public void doPurchase(int items) {
    System.out.println("Doing purchase of " + items + " Items from a brick and mortar store");
  }
}
public class Order {
  private IStore store;
  private int items;

  public void setStore(IStore store) {
    this.store = store;
  }
  public void setItems(int items) {
    this.items = items;
  }

  public void buyItems() {
    store.doPurchase(items);
  }
}

In the Order class these are two properties one reference to Istore type and another an int. There are setter methods for those properties which will be called by the Spring container to set the configured values.

If you are using XML configuration then beans are defined as given in the following XML-

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
  <!-- Store bean --> 
  <bean id="store" class="com.knpcode.SpringProject.RetailStore" />           
  <!-- Order bean with dependencies -->
  <bean id="orderBean" class="com.knpcode.SpringProject.Order">
    <property name="store" ref="store" />
    <property name="items" value="20" />
  </bean>
</beans>

For providing setter dependencies <property> tag is used.

  • When dependency is for another bean “ref” attribute is used.
  • For any primitive type or String “value” attribute is used.

You can use the following class with main method to read the configuration and call the bean method.

public class App {
  public static void main( String[] args ){
    // create context using configuration
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    Order order = (Order) context.getBean("orderBean");
    order.buyItems();
    // close the context
    context.close();
  }
}

If you want to configure setter dependencies in Spring using annotations then you will have to use @Service or @Component annotation with the classes to signify that these are Spring managed component and will be automatically discovered when component scanning is done.

Annotate setter methods with @autowired to inject the setter dependencies automatically.

@Service
public class OnlineStore implements IStore {
  public void doPurchase(int items) {
    System.out.println("Doing online purchase of " + items + " Items");
  }
}
@Service
public class RetailStore implements IStore {
  public void doPurchase(int items) {
    System.out.println("Doing purchase of " + items + " Items from a brick and mortar store");
  }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class Order {
  private IStore store;
  @Value("20")
  private int items;
  @Autowired
  @Qualifier("onlineStore")
  public void setStore(IStore store) {
    this.store = store;
  }
  public void buyItems() {
    store.doPurchase(items);
  }
}

Since there are two objects of type store so @Qualifier annotation has been used to tell which bean has to be wired otherwise you will get an error "No qualifying bean of type 'com.knpcode.SpringProject.IStore' available"

Autowiring works with references only so primitive value is provided using @Value annotation.

If you want to use XML to set up component scanning for automatically discovering beans then it can be done using following XML.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
          
  <context:component-scan base-package="com.knpcode.SpringProject" />
</beans>

XML configuration won’t have any dependencies now only <context:component-scan> tag.

Constructor-based or setter-based Dependency injection

As per Spring documentation constructor based DI is preferred over setter-based DI.

"Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency."

That's all for the topic Setter Dependency Injection in Spring. If something is missing or you have something to share about the topic please write a comment.


You may also like

Summarizing Collectors in Java Stream

In this tutorial you’ll learn about the different summarizing collectors in Java Stream API that returns a summary statistics Collectors.

Summarizing collectors in Collectors class

There are three summarizing collector methods in Collectors class which are as following-

  • summarizingInt(ToIntFunction<? super T> mapper)- Returns a Collector which applies an int-producing mapping function to each input element.
  • summarizingLong(ToLongFunction<? super T> mapper)- Returns a Collector which applies an long-producing mapping function to each input element.
  • summarizingDouble(ToDoubleFunction<? super T> mapper)- Returns a Collector which applies an double-producing mapping function to each input element.

Argument to these methods is a corresponding functional interface ToIntFunction, ToLongFunction and ToDoubleFunction that represents a function that produces respectively a int, long or double valued result.

Return type of the method used is also as per type and the Collectors returned are of type IntSummaryStatistics, LongSummaryStatistics and DoubleSummaryStatistics.

Summary statistics object that you can get by using these methods encapsulates attributes like-

  • count
  • min
  • max
  • sum
  • average

These summarizing collectors are great utility methods to compute all the above values with in a single pass.

Collectors.summarizingInt() Java example

For the examples we’ll use the Person class objects.

public class Person {
  private String name;
  private int dependents;
  private long age;
  private double weight;
  Person(String name, int dependents, long age, double weight){
    this.name = name;
    this.dependents = dependents;
    this.age = age;
    this.weight = weight;
  }
  public String getName() {
    return name;
  }
  public int getDependents() {
    return dependents;
  }

  public long getAge() {
    return age;
  }
  public double getWeight() {
    return weight;
  }
}

1. To get the summary statistics for the weight field which is of type int.

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

public class SummarizingCollectorDemo {
  public static void main(String[] args) {
    List<Person> personList = Arrays.asList(new Person("Peter", 2, 45, 75.6),
              new Person("Ram", 3, 34, 80),
              new Person("Priscilla", 1, 26, 68),
              new Person("Ajay", 4, 35, 71.5),
              new Person("Dan", 0, 58, 77.8));
    IntSummaryStatistics stats = personList.stream()
                    .collect(Collectors.summarizingInt(Person::getDependents));
    System.out.println("Total count of person- " + stats.getCount());
    System.out.println("Max dependents- " + stats.getMax());
    System.out.println("Min dependents- " + stats.getMin());
    System.out.println("Total number of dependents- " + stats.getSum());
    System.out.println("Average number of dependents- " + stats.getAverage());
  }
}
Output
Total count of person- 5
Max dependents- 4
Min dependents- 0
Total number of dependents- 10
Average number of dependents- 2.0

Collectors.summarizingLong() and Collectors.summarizingDouble() Java example

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

public class SummarizingCollectorDemo {
  public static void main(String[] args) {
    List<Person> personList = Arrays.asList(new Person("Peter", 2, 45, 75.6),
              new Person("Ram", 3, 34, 80),
              new Person("Priscilla", 1, 26, 68),
              new Person("Ajay", 4, 35, 71.5),
              new Person("Dan", 0, 58, 77.8));

    LongSummaryStatistics longSummaryStats = personList.stream()
        .collect(Collectors.summarizingLong(Person::getAge));
    
    DoubleSummaryStatistics doubleSummaryStats = personList.stream()
        .collect(Collectors.summarizingDouble(Person::getWeight));
    System.out.println("Summary statistics for age- " + longSummaryStats);
    System.out.println("Summary statistics for weight- " + doubleSummaryStats);
  }
}
Output
Summary statistics for age- LongSummaryStatistics{count=5, sum=198, min=26, average=39.600000, max=58}
Summary statistics for weight- DoubleSummaryStatistics{count=5, sum=372.900000, min=68.000000, average=74.580000, max=80.000000}

That's all for the topic Summarizing Collectors in Java Stream. If something is missing or you have something to share about the topic please write a comment.


You may also like

Generate Random Numbers Java Stream

If you are writing a Java program to generate random numbers two tried and tested ways are to either use Math.random() method or methods of Random class to get a random number but the limitation with these methods is that they generate a single random number and you would need to use them in a loop in case you need a list of random numbers. With the introduction of Java Stream API in Java 8, Random class has also been expanded to include methods that can return a stream of ints, longs or doubles which means a return type of IntStream, LongStream or DoubleStream.

Random class methods for generating streams

In Random class there are following methods for generating infinite streams-

1. ints()- Returns an effectively unlimited stream of int values.

2. ints(int randomNumberOrigin, int randomNumberBound)- Returns an effectively unlimited stream of int values within the given bounds.

Following methods restrict the generated random numbers.

1. ints(long streamSize)- Returns a stream producing the given streamSize number of int values.

2. ints(long streamSize, int randomNumberOrigin, int randomNumberBound)- Returns a stream producing the given streamSize number of int values within the given bounds.

Same set of methods also exist for producing long and double random numbers-

  • longs()
  • longs(long streamSize)
  • longs(long randomNumberOrigin, long randomNumberBound)
  • longs(long streamSize, long randomNumberOrigin, long randomNumberBound)
and
  • doubles()
  • doubles(double randomNumberOrigin, double randomNumberBound)
  • doubles(long streamSize), doubles(long streamSize, double randomNumberOrigin
  • double randomNumberBound)

Generating stream of random number examples

1. An infinite stream of integers using ints() method of the Random class. Here limit() method of Java Stream is used to limit the stream.

import java.util.Random;

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.ints().limit(10).forEach(System.out::println);
  }
}
Output
164843204
-1469424678
1335628408
29431696
267957743
-944667359
228878324
672262783
1504662080
-262691321

2. In this example we’ll generate 10 random numbers in between the lower and upper bounds of 10 and 50.

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.ints(10, 10, 51).forEach(System.out::println);
  }
}
Output
39
29
14
49
26
29
37
50
31
48

Note that with in the passed bounds lower bound is inclusive where as upper bound is exclusive that’s why to make upper bound till 50, 51 is passed as the argument.

3. If you want 10 random doubles with in the range 0 and 1.

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.doubles(10, 0, 1).forEach(System.out::println);
  }
}
Output
0.6099718485028252
0.3440097793096719
0.31985736196344106
0.6028702735888255
0.8780031623608885
0.09055972507136933
0.8280686637964826
0.7917602864784455
0.7277181639918716
0.8424139111003316

That's all for the topic Generate Random Numbers Java Stream. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java HashMap merge() With Examples

The Java HashMap merge() method is used to insert a new (key,value) pair into the HashMap or to modify value for an already existing key.

Syntax of merge() method

merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)

The parameters are-

  1. key- Key with which the resulting value has to be mapped.
  2. value- The non-null value which replaces the existing value associated with the key or inserts this new value.
  3. remappingFunction- It is an expression of type BiFunction functional interface used to recompute a value if present

merge method has the following scenarios-

  1. If the specified key is not already associated with a value associates it with the given non-null value and the (key, value) pair is inserted into the HashMap.
  2. If the specified key is associated with null value, associates it with the given non-null value.
  3. If the key already exists then replaces (or merges) the associated value with the results of the given remapping function.
  4. If the result of the given remapping function is null then removes the (key, value) pair from the HashMap.

Merge() Java examples

1. In this example a value is recomputed for the specified key. For the example a HashMap is created with product name as key and price as value. Then compute() is used to change the price (value) for the specified key.

public class MapMergeDemo {

  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 15.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // recomputing price
    products.merge("Laptop", 1200.0, (oldValue, newValue)-> oldValue- (oldValue*20/100));
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, RAM=60.5}
*** After Merge ***
{Laptop=960.0, Mouse=15.0, USB=10.45, RAM=60.5}

2. Inserting a new entry into the HashMap using merge method.

public class MapMergeDemo {
  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 15.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // Adding new key
    products.merge("Adapter", 5.0, (oldValue, newValue)-> oldValue + newValue);
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, RAM=60.5}
*** After Merge ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, Adapter=5.0, RAM=60.5}

3. If key exists but is associated with null value then using merge method value can be changed to a new value. In the example HashMap has one key with associated value as null.

public class MapMergeDemo {
  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", null);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // remappingFunction returns null
    products.merge("Mouse", 12.50, (oldValue, newValue)-> oldValue+newValue);
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=null, USB=10.45, RAM=60.5}
*** After Merge ***
{Laptop=1200.0, Mouse=12.5, USB=10.45, RAM=60.5}

4. In this example we’ll see the scenario where remappingFunction of the merge() method returns null. In that case the (key, value) pair should be removed. To verify that the function explicitly returns null in the code.

public class MapMergeDemo {

  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 8.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // remapping function returns null
    products.merge("Laptop", 1200.0, (oldValue, newValue)-> null);
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=8.0, USB=10.45, RAM=60.5}
*** After Merge ***
{Mouse=8.0, USB=10.45, RAM=60.5}

5. In this example we’ll see the merging of old value and new value. Since the remapping function gets both old and new value as arguments so we can have logic to compute value using both old and new value. In the product HashMap if price of Laptop has to be increased by 20.

public class MapMergeDemo {

  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", null);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    products.merge("Laptop", 20.0, (oldValue, newValue)-> oldValue+newValue);
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=null, USB=10.45, RAM=60.5}
*** After Merge ***
{Laptop=1220.0, Mouse=null, USB=10.45, RAM=60.5}

6. Using merge() method to recompute all values in the HashMap. In the products HashMap if you want to increase price by 10% for all the products.

public class MapMergeDemo {

  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 8.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    products.forEach((k,v) -> products.merge(k, v, (oldValue, newValue)-> oldValue+ (oldValue * 10/100)));
    System.out.println("*** After Merge ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=8.0, USB=10.45, RAM=60.5}
*** After Merge ***
{Laptop=1320.0, Mouse=8.8, USB=11.495, RAM=66.55}

Here forEach is used to iterate the Map and then merge() method is used to increase value by 10%.

That's all for the topic Java HashMap merge() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream boxed() With Examples

The boxed() method in Java Stream is used to wrap the primitive value (int, long or double) to its respective wrapper class object.

There are primitive specializations of Stream named IntStream, LongStream and DoubleStream each of these interfaces have a boxed() method that returns a Stream consisting of the elements of this stream, each boxed to an Integer, Long or Double respectively. Note that boxed() is an intermediate operation.

boxed stream Java examples

Let’s see few examples how to box a primitive value into its wrapper class using boxed() method.

1. boxed() in IntStream which is used to get a Stream consisting of the elements of this stream, each boxed to an Integer.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class BoxedIntStream {
  public static void main(String[] args) {    
    Stream<Integer> wrappedInts = IntStream.of(1, 2, 3, 4, 5).boxed();
    List<Integer> numList = wrappedInts.collect(Collectors.toList());
    System.out.println(numList);
  }
}
Output
[1, 2, 3, 4, 5]

Here IntStream having int elements first uses boxed() method to wrap these primitive ints into an object of Integer class and then use the Stream consisting of those Integer objects to convert into a List. Doing it directly won’t work, so the following statement results in compile time error.

List<Integer> numList = IntStream.of(1,2,3,4,5).collect(Collectors.toList());

2. boxed() in LongStream which is used to get a Stream consisting of the elements of this stream, each boxed to a Long.

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

public class BoxedLongStream {
  public static void main(String[] args) {
    List<Long> numList = LongStream.of(6, 7, 8, 9, 10)
          .boxed()
          .collect(Collectors.toList());
    System.out.println(numList);
  }
}
Output
[6, 7, 8, 9, 10]

3. boxed() in DoubleStream which is used to get a Stream consisting of the elements of this stream, each boxed to a Double.

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

public class BoxedDoubleStream {
  public static void main(String[] args) {
    List<Double> numList = DoubleStream.of(6, 7, 8, 9, 10)
                               .boxed()
                               .collect(Collectors.toList());
    System.out.println(numList);

  }
}
Output
[6.0, 7.0, 8.0, 9.0, 10.0]

That's all for the topic Java Stream boxed() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream concat() With Examples

If you want to merge two streams you can use concat() method in Java Stream API.

Syntax of concat() method

concat(Stream<? extends T> a, Stream<? extends T> b)

Here a represents the first stream and b represents the second stream. Method returns a stream consisting all the elements of the first stream followed by all the elements of the second stream.

The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel.

concat() method Java examples

1. Using concat() method to merge streams of Strings.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<String> stream1 = Stream.of("A", "B", "C");
    Stream<String> stream2 = Stream.of("D", "E", "F");
    Stream<String> mergedStream = Stream.concat(stream1, stream2);
    mergedStream.forEach(System.out::println);
  }
}
Output
A
B
C
D
E
F

2. Using concat method to merge more than 2 streams. You can also layer the concat() method to merge more than two streams, in the following example 4 streams are concatenated.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<Integer> stream1 = Stream.of(1, 2, 3);
    Stream<Integer> stream2 = Stream.of(4, 5, 6);
    Stream<Integer> stream3 = Stream.of(7, 8, 9);
    Stream<Integer> stream4 = Stream.of(10, 11, 12);
    Stream<Integer> mergedStream = Stream.concat(stream1, 
            Stream.concat(Stream.concat(stream2, stream3), stream4));
    mergedStream.forEach(e -> System.out.print(e + " "));
  }
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 

3. Using concat() with other stream operations. A very common scenario is to merge two streams and get only the distinct elements, that can be done by using distinct() in Java stream.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
    Stream<Integer> stream2 = Stream.of(4, 4, 3, 1, 8, 6);

    Stream<Integer> mergedStream = Stream.concat(stream1, stream2).distinct();
    mergedStream.forEach(e -> System.out.print(e + " "));
  }
}
Output
1 2 3 4 5 6 8 

That's all for the topic Java Stream concat() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java HashMap compute() With Examples

The Java HashMap compute() method is used to compute a new value for the specified key.

Syntax of compute() method

compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

The parameters are-

  1. key- Key with which the computed value has to be mapped.
  2. remappingFunction- It is an expression of type BiFunction functional interface used to compute a value.

Method returns a new value associated with the specified key or null if there is no new values. If the remapping function returns null, the mapping is removed (or remains absent if initially absent).

compute() method Java examples

1. In this example a new value is computed for the specified key. For the example a HashMap is created with product name as key and price as value. Then compute() is used to change the price (value) for the specified key.

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

public class MapComputeDemo {
  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 15.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // Laptop at 20% discount
    products.compute("Laptop", (k, v)-> v- (v*20/100));
    System.out.println("*** After Compute ***");
    System.out.println(products);
    
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, RAM=60.5}
*** After Compute ***
{Laptop=960.0, Mouse=15.0, USB=10.45, RAM=60.5}

2. In this example we’ll see what happens if the remappingFunction returns null. In that case the (key, value) pair should be removed. To verify that the function explicitly returns null in the code.

public class MapComputeDemo {
  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 15.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    // remappingFunction returns null
    products.compute("Laptop", (k, v)-> null);
    System.out.println("*** After Compute ***");
    System.out.println(products);
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, RAM=60.5}
*** After Compute ***
{Mouse=15.0, USB=10.45, RAM=60.5}

As you can see the product “Laptop” is removed.

3. Using compute() method to compute all values in the HashMap. In the products HashMap if you want to increase price by 10% for all the products.

public class MapComputeDemo {
  public static void main(String[] args) {
    Map<String, Double> products = new HashMap<>();
    products.put("Laptop", 1200.0);
    products.put("RAM", 60.50);
    products.put("USB", 10.45);
    products.put("Mouse", 15.0);
    System.out.println("*** Initial Values ***");
    System.out.println(products);
    products.forEach((k,v) -> products.compute(k, (key, value)-> value + (value*10/100)));
    System.out.println("*** After Compute ***");
    System.out.println(products);
    
  }
}
Output
*** Initial Values ***
{Laptop=1200.0, Mouse=15.0, USB=10.45, RAM=60.5}
*** After Compute ***
{Laptop=1320.0, Mouse=16.5, USB=11.495, RAM=66.55}

That's all for the topic Java HashMap compute() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Map#putIfAbsent() in Java With Examples

In this tutorial you will see how to use putIfAbsent() method in Java HashMap. The putIfAbsent() method inserts the specified value if the passed key is not already present in the HashMap or the key is null. Using this method gives you an option to check if key is already present or not, before associating a value with the key. What this method does in a single statement can be explained as-

 V v = map.get(key);
 if (v == null)
     v = map.put(key, value);

 return v;

Syntax of putIfAbsent() method

V putIfAbsent(K key, V value)

Here the parameters are-

  • key- key with which the specified value is to be associated
  • value- value to be associated with the specified key

This method returns the previous value if key is already associated with a value or null if there was no existing mapping for the key. Method also returns null if key was previously inserted as null in the HashMap.

Note that the default implementation of the putIfAbsent() method in the Map interface makes no guarantees about synchronization or atomicity properties of this method. Implementation of putIfAbsent() in the ConcurrentHashMap guarantees atomicity.

putIfAbsent() Java examples

1. In the following example we’ll try to insert a new value with an existing key.

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

public class MapPutIfAbsent {

  public static void main(String[] args) {
      Map<String, String> carMap = new HashMap<String, String>();
      // Storing elements
      carMap.put("1", "Audi");
      carMap.put("2", "BMW");
      carMap.put("3", "Jaguar");
      String val = carMap.putIfAbsent("3", "Mini Cooper");
      System.out.println("Value is- " + val);
      System.out.println(carMap);
  }
}
Output
Value is- Jaguar
{1=Audi, 2=BMW, 3=Jaguar}

As you can see since the key is already present in the HashMap so the value is not rewritten. Also note that the putIfAbsent() is returning the already associated value.

2. In the following example we’ll try to insert a value with a key that doesn’t already exist.

public class MapPutIfAbsent {
  public static void main(String[] args) {
    Map<String, String> carMap = new HashMap<String, String>();
    // Storing elements
    carMap.put("1", "Audi");
    carMap.put("2", "BMW");
    carMap.put("3", "Jaguar");
    String val = carMap.putIfAbsent("4", "Mini Cooper");
    System.out.println("Value is- " + val);
    System.out.println(carMap);
  }
}
Output
Value is- null
{1=Audi, 2=BMW, 3=Jaguar, 4=Mini Cooper}

As you can see from the output value is added to the HashMap along with the new key. putIfAbsent() method returns null because there was no existing mapping for the key.

3. In the following example we’ll try to insert a value with a key as null when there is already a value with null key.

public class MapPutIfAbsent {

  public static void main(String[] args) {
    Map<String, String> carMap = new HashMap<String, String>();
      // Storing elements
      carMap.put("1", "Audi");
      carMap.put("2", "BMW");
      carMap.put("3", "Jaguar");
      carMap.put(null, "Volks Wagon");
      String val = carMap.putIfAbsent(null, "Mini Cooper");
      System.out.println("Value is- " + val);
      System.out.println(carMap);
  }
}
Output
Value is- Volks Wagon
{null=Volks Wagon, 1=Audi, 2=BMW, 3=Jaguar}

As you can see new value is inserted now since the previous value was mapped to null. Return value of the putIfAbsent() method is the previous value.

That's all for the topic Map#putIfAbsent() in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream count() With Examples

In Java Stream API there is a count() method that returns the count of elements in the stream. In this tutorial you’ll learn about count() method with the help of some examples.

Java Stream count() method

Syntax of the count() method is as follows-

long count()

count method is a special case of a reduction operation as it takes a sequence of input elements and combines them into a single summary result. This method is a terminal operation meaning it produces a result and stream pipeline is considered consumed, and can no longer be used after count operation.

count() method Java examples

1. Using count() to get the number of elements in a List by using list as a Stream source.

import java.util.Arrays;
import java.util.List;

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 4, 12, 16, 0, 7, 6);
    long result = numList.stream().count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 8

2. You can also use count() method along with other operations to get the count of stream elements after applying other operations. In the following example first filter() method is used to filter out elements as per the given condition (elements should be greater than 10) then count() is used to get the count of elements in the stream after applying filter operation.

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 4, 12, 16, 0, 7, 6);
    long result = numList.stream().filter(e -> e > 10).count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 2

3. In the following example count() is used to get the count of distinct elements.

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 5, 12, 16, 12, 3, 6);
    long result = numList.stream().distinct().count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 5

That's all for the topic Java Stream count() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream – Convert a Stream to Map

In this tutorial you’ll see how to convert a Stream to Map using collector method and utility methods like toMap() and groupingBy() of Collectors class in Java Stream API.

Syntax of toMap() method is as given below-

toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)

This method returns a Collector that accumulates elements into a Map. Both of the arguments passed to the method are of type Function which is a functional interface. Using these mapping functions keyMapper and valueMapper, keys and values of the resulting Map are calculated.

1. Using Collectors.toMap() method

In the following example a list of students is collected to a Map where key is the student’s roll number and value is Student name.

Student class used is-

public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public String getName() {
    return name;
  }

  public String getStream() {
    return stream;
  }

  public int getMarks() {
    return marks;
  }

  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class StreamToMap {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 73),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 76));
    Map<Integer, String> studentMap = studentList.stream()
                          .collect(Collectors.toMap(Student::getRollNo, Student::getName));  
    System.out.println(studentMap);
  }
}
Output
{1=Mercy, 2=Ram, 3=Priscilla, 4=Jacques, 5=Peter}

If you want to collect to a Map where key is the student’s roll number and value is the student object then it can be done as. Here utility method Function.identity() is used which returns a function that always returns its input argument.

public class StreamToMap {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 73),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 76));
    Map<Integer, Student> studentMap = studentList.stream()
                          .collect(Collectors.toMap(Student::getRollNo, Function.identity()));  
    System.out.println(studentMap);
  }
}
Output
{1=Roll Number: 1 Name: Mercy Marks: 73, 2=Roll Number: 2 Name: Ram Marks: 99, 3=Roll Number: 3 Name: Priscilla Marks: 68, 4=Roll Number: 4 Name: Jacques Marks: 97, 5=Roll Number: 5 Name: Peter Marks: 76}

2. Using Collectors.groupingBy() method

groupingBy() method also collects elements into a map by dividing elements into two lists of elements as per the passed grouping function. The collector produces a Map<K, List> where key specifies a group and List contains the elements which map to the associated key.

public class StreamToMap {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Mahesh", "Art", 62),
              new Student(5, "Scott", "Commerce", 72));
      Map<String, List<Student>> names = studentList.stream()
          .collect(Collectors.groupingBy(Student::getStream));
      // Iterating the returned Map
      names.entrySet().forEach(es->{System.out.println("Stream- " + es.getKey());
      System.out.println("**Students**");
      es.getValue().forEach(e->System.out.println(e.getName()));});
  }
}
Output
Stream- Art
**Students**
Priscilla
Mahesh
Stream- Science
**Students**
Peter
Ram
Stream- Commerce
**Students**
Scott

That's all for the topic Java Stream – Convert a Stream to Map. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream peek() With Examples

In this tutorial we’ll see how to use Java Stream peek() method with the help of few examples.

Syntax of peek() method in Java Stream API

Stream<T> peek(Consumer<? super T> action)

Argument passed to the peek method is of type Consumer functional interface which represents a non-interfering action to perform on the elements as they are consumed from the stream. Method returns a new Stream.

peek() is an intermediate operation which means using peek() without any terminal operation will do nothing.

Java 9 onward, if the number of elements in Stream source is known in advance then no source elements will be traversed and no intermediate operations like peek() will be evaluated. This is a performance optimization.

peek() method exists mainly to support debugging, where you want to see the elements as they flow from one operation to another with in the Stream pipeline.

Java Stream peek() examples

1. In this example peek() method is used to display the stream elements after each operation.

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

public class StreamPeek {

  public static void main(String[] args) {
     List<String> tempList = Stream.of("one", "two", "three", "four", "five")
         .filter(e -> e.length() > 3)
         .peek(e -> System.out.println("Filtered value: " + e))
         .map(String::toUpperCase)
         .peek(e -> System.out.println("Mapped value: " + e))
         .collect(Collectors.toList());
     
     System.out.println(tempList);
  }
}
Output
Mapped value: THREE
Filtered value: four
Mapped value: FOUR
Filtered value: five
Mapped value: FIVE
[THREE, FOUR, FIVE]

As you can see peek() method is a good way to debug your Stream and see the results of the operation on the Stream.

2. If you don’t have a terminal operation, intermediate operations like peek() are not executed. You can see that by removing the collect() operation from the previous example.

public class StreamPeek {

  public static void main(String[] args) {
    Stream.of("one", "two", "three", "four", "five")
           .filter(e -> e.length() > 3)
           .peek(e -> System.out.println("Filtered value: " + e))
           .map(String::toUpperCase)
           .peek(e -> System.out.println("Mapped value: " + e));
  }
}
On executing it you won’t get any output.

That's all for the topic Java Stream peek() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Exception Propagation in Java

In the execution of the method code, if an exception condition occurs, normal flow of the method is disrupted. In order to handle the exceptional condition an exception object is created and thrown. That exception may be handled in the method where that exception is thrown or it may be passed on to be handled by other methods in the caller stack. This process of going through the method call stack to look for an exception handler that can handle the thrown exception is known as exception propagation in Java.

Exception propagation in Java

To reach to a certain method in the code, some other methods are called in between. This list of methods is known as the method call stack.

When an exception occurs in the current method, exception handling mechanism will look for an exception handler in the current method, if not found it will go to the previous method (caller method of the current method) in the call stack and so on looking for the exception handler that can handle the thrown exception.

If no exception handler is provided for the thrown exception, default exception handler will be called to handle that exception.

Exception Propagation flow

Suppose you have a call stack of three methods method1, method2 and method3. From method1 you call method2 and method3 is called from method2.

If an exception occurs in method 3 and the exception handler is in method1 then the exception propagation in Java can be shown as follows-

exception propagation in java

Exception Propagation in Java with checked and unchecked exceptions

In case of unchecked exception it is not enforced to handle the exception using try-catch block or throws clause so exception propagation happens by default.

In case of checked exception you will have to declare the exception that are not handled with in a method by using throws keyword. That is an indication that exception has to be propagated to the caller method. If caller method wishes to propagate it further then it can also declare the thrown exceptions using the throws keyword.

Exception propagation Java example with unchecked exception

Let’s take the same method hierarchy of three methods as depicted above. Where exception occurs in method3 and propagates to method1 in search of an appropriate exception handler.

public class ExceptionPropagationDemo {
  public static void main(String[] args) {
    ExceptionPropagationDemo ep = new ExceptionPropagationDemo();
    ep.method1();
  }
  // This method forwards the exception
  void method3(){
    System.out.println("In method3");
    int[] numArr = {4,5,6};
    int number = numArr[5];
  }

  // This method forwards the exception
  void method2(){
    System.out.println("In method2");
    method3();
  }
	
  // Exception is handled in this method
  void method1(){
    try{
      System.out.println("In method1");
      method2();
    } catch(Exception e){
      System.out.println("Exception handled");
      e.printStackTrace();
    }
  }
}
Output
In method1
In method2
In method3
Exception handled
java.lang.ArrayIndexOutOfBoundsException: 5
	at com.knpcode.ExceptionPropagationDemo.method3(ExceptionPropagationDemo.java:14)
	at com.knpcode.ExceptionPropagationDemo.method2(ExceptionPropagationDemo.java:20)
	at com.knpcode.ExceptionPropagationDemo.method1(ExceptionPropagationDemo.java:27)
	at com.knpcode.ExceptionPropagationDemo.main(ExceptionPropagationDemo.java:7)

In the above code exception occurs in method3 as there is an attempt to get the value at the index 5 of an array whose length is 3. This will result in ArrayIndexOutOfBoundsException being thrown. Since method3 does not provide any exception handling mechanism so next method (method 2) is searched, there also no exception handling mechanism is found so exception propagates to method1 where it is handled. You can see the same flow in the exception trace where exception originates in method3 and propagates to method1.

Exception propagation Java example with checked exception

In case of checked exception you need to explicitly specify the exceptions using throws clause if you are not providing exception handling with in the method.

Let’s see an example of exception propagation with checked exceptions. Here in method 3 there is a code to read a file and stream is also closed both of these activities may result in checked exception. Since you are forced to handle that exception so you specify it using throws clause. Notice that method2 is not providing exception handling so there also it is specified using throws clause. That way exception propagates to method1 where it is handled.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class ExceptionPropagationDemo {
  public static void main(String[] args) {
    ExceptionPropagationDemo ep = new ExceptionPropagationDemo();
    ep.method1();
  }
  // This method forwards the exception
  void method3() throws IOException{
    System.out.println("In method3");
    BufferedReader br = null;
    try{
      br = new BufferedReader(new
          InputStreamReader(new FileInputStream(new 
              File("D:\\test1.txt"))));
    }finally{
      if(br != null)
        br.close();
    }		
  }
	
  // This method forwards the exception
  void method2() throws IOException{
    System.out.println("In method2");
    method3();
  }
	
  // Exception is handled in this method
  void method1(){
    try{
      System.out.println("In method1");
      method2();
    } catch(IOException e){
      System.out.println("Exception handled");
      e.printStackTrace();
    }
  }
}
Output
In method1
In method2
In method3
Exception handled
java.io.FileNotFoundException: D:\test1.txt (The system cannot find the file specified)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(Unknown Source)
	at java.io.FileInputStream.(Unknown Source)
	at com.knpcode.ExceptionPropagationDemo.method3(ExceptionPropagationDemo.java:22)
	at com.knpcode.ExceptionPropagationDemo.method2(ExceptionPropagationDemo.java:34)
	at com.knpcode.ExceptionPropagationDemo.method1(ExceptionPropagationDemo.java:41)
	at com.knpcode.ExceptionPropagationDemo.main(ExceptionPropagationDemo.java:13)

That's all for the topic Exception Propagation in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream – Convert a Stream to Set

In this tutorial you’ll see how to convert a Stream to Set using collector method and utility methods like toSet() and toCollection() of Collectors class in Java Stream API.

1. A simple example to collect Stream elements into a HashSet.

import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamToSet {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    Set<String> setFromStream = streamElem.collect(Collectors.toSet());
    // get type of object
    System.out.println(setFromStream.getClass().getName());
    System.out.println("Elements in the Set- " + setFromStream);
  }
}
Output
java.util.HashSet
Elements in the Set- [A, B, C, D]

As you can see type of the Set returned is java.util.HashSet.

2. If you want to convert the Stream into another implementation of Set say TreeSet then you can use Collectors.toCollection() method.

public class StreamToSet {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    Set<String> setFromStream = streamElem.collect(
            Collectors.toCollection(TreeSet::new));
    // get type of object
    System.out.println(setFromStream.getClass().getName());
    System.out.println("Elements in the Set- " + setFromStream);
  }
}
Output
java.util.TreeSet
Elements in the Set- [A, B, C, D]

As you can see now the type of the Set is java.util.TreeSet.

3. Converting Stream to Set while filtering some of the elements by providing a condition. For example if you want to store only those elements in the Set which are greater than 10 then you can filter other elements.

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

public class StreamToSet {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    Set<Integer> setFromStream = numList.stream()
                                        .filter(e -> e > 8)
                                        .collect(Collectors.toSet());
    System.out.println("Elements in the Set- " + setFromStream);
  }
}
Output
Elements in the Set- [22, 10, 12]

In this example we start with a List of integers and use filter() method to filter elements and the returned Stream is converted to a Set.

4. An example with custom object to store the name of only those Students in the Set who have scored more than 75. Let’s say requirement is to store the student names in sorted order for that we can use TreeSet.

Student class used is as follows-

public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public String getName() {
    return name;
  }

  public String getStream() {
    return stream;
  }

  public int getMarks() {
    return marks;
  }

  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
}
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

public class StreamToSet {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 73),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 76));
    Set<String> nameSet = studentList.stream()
                     .filter(s -> s.getMarks() > 75)
                     .map(s -> s.getName())
                     .collect(Collectors.toCollection(TreeSet::new));
    System.out.println("Elements in the Set- " + nameSet);
  }
}
Output
Elements in the Set- [Jacques, Peter, Ram]

That's all for the topic Java Stream – Convert a Stream to Set. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream - Convert a Stream to List

In this tutorial you’ll see how to convert a Stream to list using collector method and utility methods like toList() and toCollection() of Collectors class in Java Stream API.

1. A simple example to collect Stream elements into an ArrayList.

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

public class StreamToList {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    List<String> listFromStream = streamElem.collect(Collectors.toList());
    System.out.println(listFromStream.getClass().getName());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
java.util.ArrayList
Elements in the list- [A, B, C, D]

As you can see type of the List returned is ArrayList.

2. If you want to convert the Stream into a LinkedList then you can use Collectors.toCollection() method.

public class StreamToList {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    List<String> listFromStream = streamElem.collect(Collectors.toCollection(LinkedList :: new));
    System.out.println(listFromStream.getClass().getName());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
java.util.LinkedList
Elements in the list- [A, B, C, D]

As you can see now the type of the List is LinkedList.

3. Converting Stream to List while filtering some of the elements by providing a condition. For example if you want to store only those elements in the List which are greater than 10 then you can filter other elements.

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

public class StreamToList {
  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    List<Integer> listFromStream = numList.stream().filter(e -> e > 10).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [12, 22]

4. An example with custom object to store only those Students in the List who have scored more than 90.

Student class used is as follows-
public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public String getName() {
    return name;
  }

  public String getStream() {
    return stream;
  }

  public int getMarks() {
    return marks;
  }

  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
}
public class StreamToList {
  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 75));
    List<Student> listFromStream = studentList.stream().filter(s -> s.getMarks() > 90).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [Roll Number: 2 Name: Ram Marks: 99, Roll Number: 4 Name: Jacques Marks: 97]

5. If you want to get only the student names in the list then you can use map method along with collect.

public class StreamToList {
  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 75));
    List<String> listFromStream = studentList.stream().map(s -> s.getName()).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [Mercy, Ram, Priscilla, Jacques, Peter]

That's all for the topic Java Stream - Convert a Stream to List. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Stream - Get Last Element

In this tutorial we’ll see what options are there to get the last element of the stream using the Java Stream API.

1. Using reduce() method

reduce method in the Java Stream API is used to perform a reduction on the elements of the stream so that the stream is reduced to a single value. Thus it can be used to reduce the stream to a last value.

import java.util.Arrays;
import java.util.List;

public class StreamLastDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12);
    int lastElement = numList.stream().reduce((f, s) -> s).orElse(-1);
    System.out.println("Last element in the Stream- " + lastElement);
  }
}
Output
Last element in the Stream- 12

2. Using skip() method

You can also use skip method to skip to the last element and then return that element. This approach is not very efficient though.

public class StreamLastDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    // get the stream element count
    long elementCount = numList.stream().count();
    int lastElement = -1;
    // Return -1 if not able to find last element
    if(elementCount != 0) {
      lastElement = numList.stream().skip(elementCount - 1)
                        .findFirst()
                        .orElseThrow(()->new RuntimeException("Exception Occurred"));
    }
    System.out.println("Last element in the Stream: " + lastElement);
  }
}

Output
Last element in the Stream: 22

3. Using Streams.findLast() method of Guava library

In Guava library there is a Streams class with many utility methods to be used with Stream instances. There is a findLast() method to get the last element of the stream.

import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Streams;

public class StreamLastDemo {

  public static void main(String[] args) {
    List numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    int lastElement = Streams.findLast(numList.stream()).orElse(-1);
    System.out.println("Last element in the Stream: " + lastElement);
  }
}
Output
Last element in the Stream: 22

That's all for the topic Java Stream - Get Last Element. If something is missing or you have something to share about the topic please write a comment.


You may also like

flatMap() in Java Stream

When you use map operations in Java Stream resulting stream is obtained by applying the given function to all the elements of this stream. Java Stream API also provides a flatMap() method that apart from applying the given function to all the elements of this stream, flattens the resulting elements too so that all the nested elements are at the same level.

flatMap is an intermediate operation.

flatMap method signature

<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

Here mapper is a non-interfering, stateless function applied to each element of the stream.

R is the element type of the new stream.

flatMap Java examples

Let’s try to understand with few examples how flatMap() flattens the structure and how it helps.

Suppose there is an ArrayList that contains ArrayLists in turn and you want to count the total number of elements in the list. If you use map function then you will get the number of elements as 2 because map function will get each nested list as element of the stream.

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    long noOfElements = list.stream().map(a -> a.stream()).count();
    System.out.println("Number of elements- "+ noOfElements);
  }
}
Output
Number of elements- 2

When you use flatMap function, structure is flattened so that the number of elements is counted properly.

public class FlatMapExample {

  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    long noOfElements = list.stream().flatMap(a -> a.stream()).count();
    System.out.println("Number of elements- "+ noOfElements);
  }
}
Output
Number of elements- 4

If you want to display elements in nested ArrayLists in uppercase using map function returns List<Stream<String>>

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    List<Stream<String>> resultlist = list.stream()
                              .map(a -> a.stream()
                              .map(String::toUpperCase))
                              .collect(Collectors.toList());
    resultlist.forEach(a -> a.forEach(System.out::println));
  }
}

If you use flatMap in such scenario both lists are flattened so the return value is List

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    List<String> resultlist = list.stream()
                        .flatMap(a -> a.stream()
                        .map(String::toUpperCase))
                        .collect(Collectors.toList());
    resultlist.forEach(System.out::println);
  }
}
Output
A
B
C
D

Here is another example where we have a List of lists. There is a class Order which has a field items of type List. Now you want to display all the items in all the orders.

public class Order {
  private String orderId;
  private List<String> items;
  public String getOrderId() {
    return orderId;
  }
  public void setOrderId(String orderId) {
    this.orderId = orderId;
  }
  public List<String> getItems() {
    return items;
  }
  public void setItems(List<String> items) {
    this.items = items;
  }
}
public class FlatMapExample {
  public static void main(String[] args) {
    // Create list of orders
    List<Order> listOfOrders = new ArrayList<Order>();
    Order order = new Order();
    order.setOrderId("1");
    order.setItems(Arrays.asList("Book", "Shoes", "Watch"));
    listOfOrders.add(order);
    order = new Order();
    order.setOrderId("2");
    order.setItems(Arrays.asList("Mobile", "Book"));
    listOfOrders.add(order);

    List<String> listOfItems = listOfOrders.stream()
                          .flatMap(o -> o.getItems()
                          .stream())
                          .collect(Collectors.toList());
    listOfItems.forEach(System.out::println);
  }
}
Output
Book
Shoes
Watch
Mobile
Book

flatMap for primitive type stream

There are also flatMap() variants to be used for getting primitive type streams in Java.

  • flatMapToInt(Function<? super T,? extends IntStream> mapper)- Returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
  • flatMapToLong(Function<? super T,? extends LongStream> mapper)- Returns a LongStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
  • flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)- Returns a DoubleStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.

flatMapToInt Java example

Getting an IntStream by flattening a two dimensional array.

int[][] numbers = {{7,8}, {4,5}, {3,4}};
IntStream iStream = Stream.of(numbers).flatMapToInt(n -> Arrays.stream(n));
iStream.forEach(System.out::println);
Output
7
8
4
5
3
4

That's all for the topic flatMap() in Java Stream. If something is missing or you have something to share about the topic please write a comment.


You may also like