Showing posts with label java8. Show all posts
Showing posts with label java8. Show all posts

Monday, 8 May 2023

Introduction to Spliterator interface in Java

Spliterator instance is used to traverse and partition the elements of a source. Array, Collection, IOChannel etc., come under spliterator source.

 

Example 1: Traverse the List elements using spliterator.

List<Integer> primesList = Arrays.asList(2, 3, 5, 7, 11);
primesList.spliterator().forEachRemaining(System.out::println);

Example 2: Partition the elements of spliterator.

'trySplit' method splits the current spliterator’s elements into two parts if possible and returns a new Spliterator object covering some portion of the elements, or null if this spliterator cannot be split.

 

SpliteratorPartition.java

package com.sample.app;

import java.util.Arrays;
import java.util.Spliterator;

public class SpliteratorPartition {

	public static void main(String[] args) {

		Spliterator<Integer> spliterator1 = Arrays.asList(2, 3, 5, 7, 11, 13).spliterator();
		Spliterator<Integer> spliterator2 = spliterator1.trySplit();

		System.out.println("Elements in spliterator 1");
		spliterator1.forEachRemaining(System.out::println);

		System.out.println("\nElements in spliterator 2");
		spliterator2.forEachRemaining(System.out::println);
	}

}

Output

Elements in spliterator 1
7
11
13

Elements in spliterator 2
2
3
5

As you see above output, spliterator1 is initially hold 6 elements (2, 3, 5, 7, 11, 13). After the split, spliterator1 holds (7, 11, 13) and spliterator 2 holds (2, 3, 5).

 

Spliterator traversal

You can traverse the spliterator in two ways.

a. Traverse individually using tryAdvance method

b. Traverse sequentially in bulk using forEachRemaining method

 

Traverse individually using tryAdvance method

while (spliterator1.tryAdvance(element -> System.out.println(element))) {}

 

Find the below working application.

 

SpliteratorTraverseOneByOne.java

package com.sample.app;

import java.util.Arrays;
import java.util.Spliterator;

public class SpliteratorTraverseOneByOne {

	public static void main(String[] args) {

		Spliterator<Integer> spliterator1 = Arrays.asList(2, 3, 5, 7, 11, 13).spliterator();

		while (spliterator1.tryAdvance(element -> System.out.println(element))) {
			
		}
			
	}

}

Output

2
3
5
7
11
13

Traverse sequentially in bulk using forEachRemaining method

Example

spliterator1.forEachRemaining(System.out::println);

SpliteratorTraverseInBulk.java

package com.sample.app;

import java.util.Arrays;
import java.util.Spliterator;

public class SpliteratorTraverseInBulk {
	
	public static void main(String[] args) {

		Spliterator<Integer> spliterator1 = Arrays.asList(2, 3, 5, 7, 11, 13).spliterator();

		spliterator1.forEachRemaining(System.out::println);

	}
}

Output

2
3
5
7
11
13

Split the data using trySplit method

'trySplit' method splits the current spliterator’s elements into two parts if possible and returns a new Spliterator object covering some portion of the elements, or null if this spliterator cannot be split. You can depict the same from below figure.




Find the below working application.

 

SpliteratorTrySplit.java


package com.sample.app;

import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;

public class SpliteratorTrySplit {

	private static List<Integer> nElements(int noOfElements) {
		List<Integer> result = new ArrayList<>();

		for (int i = 1; i < noOfElements + 1; i++) {
			result.add(i);
		}

		return result;

	}

	private static void printElements(Spliterator<?> spliterator, String message) {
		System.out.println(message);
		spliterator.forEachRemaining(ele -> System.out.print(ele + " "));
		System.out.println();
	}

	public static void main(String[] args) {
		List<Integer> list1 = nElements(16);

		Spliterator<Integer> spliterator1 = list1.spliterator();
		printElements(spliterator1, "spliterator1 elements");

		System.out.println("\nSplit the spliterator once");
		spliterator1 = list1.spliterator();
		Spliterator<Integer> spliterator2 = spliterator1.trySplit();
		printElements(spliterator1, "spliterator1 elements");
		printElements(spliterator2, "spliterator2 elements");

		System.out.println("\nSplit the spliterator1 twice and spliterator2 twice");
		spliterator1 = list1.spliterator();
		spliterator2 = spliterator1.trySplit();
		Spliterator<Integer> spliterator3 = spliterator1.trySplit();
		Spliterator<Integer> spliterator4 = spliterator2.trySplit();
		printElements(spliterator1, "spliterator1 elements");
		printElements(spliterator2, "spliterator2 elements");
		printElements(spliterator3, "spliterator3 elements");
		printElements(spliterator4, "spliterator4 elements");

	}

}

Output

spliterator1 elements
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 

Split the spliterator once
spliterator1 elements
9 10 11 12 13 14 15 16 
spliterator2 elements
1 2 3 4 5 6 7 8 

Split the spliterator1 twice and spliterator2 twice
spliterator1 elements
13 14 15 16 
spliterator2 elements
5 6 7 8 
spliterator3 elements
9 10 11 12 
spliterator4 elements
1 2 3 4

Spliterator Characteristics

A Spliterator reports a set of characteristics of its structure, source, and elements. Following table summarizes the characteristics of the spliterator.

 

Characteristic

Description

ORDERED

Iterate over the elements in order.

DISTINCT

For each pair of encountered elements x, y, !x.equals(y). This applies for example, to a Spliterator based on a Set.

SORTED

Characteristic value signifying that encounter order follows a defined sort order.

SIZED

Characteristic value signifying that the value returned from estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal.

NONNULL

Characteristic value signifying that the source guarantees that encountered elements will not be null. (This applies, for example, to most concurrent collections, queues, and maps.)

IMMUTABLE

Characteristic value signifying that the element source cannot be structurally modified; that is, elements cannot be added, replaced, or removed, so such changes cannot occur during traversal. A Spliterator that does not report IMMUTABLE or CONCURRENT is expected to have a documented policy (for example throwing ConcurrentModificationException) concerning structural interference detected during traversal.

CONCURRENT

Characteristic value signifying that the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization. If so, the Spliterator is expected to have a documented policy concerning the impact of modifications during traversal.

SUBSIZED

Characteristic value signifying that all Spliterators resulting from trySplit() will be both SIZED and SUBSIZED. This means that all child Spliterators, whether direct or indirect, will be SIZED.

 

 

Find the below working application to get the characteristics of a spliterator.

 

SpliteratorCharacterstics.java

package com.sample.app.streams;

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

public class SpliteratorCharacterstics {

	public static void main(String[] args) {
		List<Integer> primesList = Arrays.asList(2, 3, 5, 7, 11);
		Spliterator<Integer> spliterator = primesList.spliterator();

		System.out.println("is ORDERED ? " + spliterator.hasCharacteristics(Spliterator.ORDERED));
		System.out.println("is DISTINCT ? " + spliterator.hasCharacteristics(Spliterator.DISTINCT));
		System.out.println("is SORTED ? " + spliterator.hasCharacteristics(Spliterator.SORTED));
		System.out.println("is SIZED ? " + spliterator.hasCharacteristics(Spliterator.SIZED));
		System.out.println("is NONNULL ? " + spliterator.hasCharacteristics(Spliterator.NONNULL));
		System.out.println("is IMMUTABLE ? " + spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
		System.out.println("is CONCURRENT ? " + spliterator.hasCharacteristics(Spliterator.CONCURRENT));
		System.out.println("is SUBSIZED ? " + spliterator.hasCharacteristics(Spliterator.SUBSIZED));

	}

}

Output

is ORDERED ? true
is DISTINCT ? false
is SORTED ? false
is SIZED ? true
is NONNULL ? false
is IMMUTABLE ? false
is CONCURRENT ? false
is SUBSIZED ? true


 

Previous                                                 Next                                                 Home

Friday, 26 March 2021

How to flatten nested maps recursively?

Using ‘flatmap’ function of a stream, you can flatten the nested maps recursively.

 

Find the below working application.

 

FlatMapUtil.java

package com.sample.app;

import java.util.AbstractMap.SimpleEntry;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class FlatMapUtil {
	public static Map<String, Object> flatten(Map<String, Object> mapToFlatten) {
		return mapToFlatten.entrySet().stream().flatMap(FlatMapUtil::flatten).collect(LinkedHashMap::new,
				(map, entry) -> map.put(entry.getKey(), entry.getValue()), LinkedHashMap::putAll);
	}

	private static Stream<Entry<String, Object>> flatten(Map.Entry<String, Object> entry) {

		if (entry == null) {
			return Stream.empty();
		}

		Object value = entry.getValue();

		if (value instanceof Map<?, ?>) {
			Map<?, ?> properties = (Map<?, ?>) value;
			return properties.entrySet().stream()
					.flatMap(e -> flatten(new SimpleEntry<>(entry.getKey() + "." + e.getKey(), e.getValue())));
		}

		if (value instanceof List<?>) {
			List<?> list = (List<?>) value;
			return IntStream.range(0, list.size())
					.mapToObj(i -> new SimpleEntry<String, Object>(entry.getKey() + "[" + i + "]", list.get(i)))
					.flatMap(FlatMapUtil::flatten);
		}

		return Stream.of(entry);
	}
}

 

FlatMapDemo.java

package com.sample.app;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FlatMapDemo {
	public static void main(String args[]) {
		Map<String, Object> employeeDetails = new HashMap<>();

		Map<String, Object> emp1Details = new HashMap<>();

		Map<String, String> name = new HashMap<>();
		name.put("firstName", "Krishna");
		name.put("lastName", "Gurram");
		emp1Details.put("name", name);

		Map<String, Object> address1 = new HashMap<>();
		address1.put("city", "Bangalore");
		address1.put("state", "Karnataka");
		address1.put("country", "India");

		List<Map<String, Object>> emp1Addresses = new ArrayList<>();
		emp1Addresses.add(address1);

		emp1Details.put("addresses", emp1Addresses);

		employeeDetails.put("emp1", emp1Details);

		Map<String, Object> map = FlatMapUtil.flatten(employeeDetails);

		for (String key : map.keySet()) {
			System.out.println(key + " -> " + map.get(key));
		}

	}
}

 

Output

emp1.addresses[0].country -> India
emp1.addresses[0].city -> Bangalore
emp1.addresses[0].state -> Karnataka
emp1.name.firstName -> Krishna
emp1.name.lastName -> Gurram

 

 

 

 

  

Previous                                                    Next                                                    Home

Thursday, 28 January 2021

Java8: Compact Profiles

Java8 provides a feature that enables Java Applications to use subset of the APIs provided by entire JDK. This feature is called compact profiles. Using compact profiles, we can deploy the application with the subset APIs instead of entire JDK APIs.

 

Why Compact Profiles?

Prior to Java8, to deploy a Java application, we need to deploy entire Java APIs also. With compact profiles, we can reduce memory footprint by deploying only subset profile. Compact profiles are interim solution to Java9 modularity system (Project Jigsaw).

 

Java8 defines 3 compact profiles (compact1, compact2 and compact3). Each profile is a subset of its predecessor. For example, compact2 contains all the copact1 packages plus some new packages.

 


Following table summarizes the compact profiles and their comprising packages.

 

compact1

compact2

compact3

java.io

 

java.lang

 

java.lang.annotation

 

java.lang.invoke

 

java.lang.ref

 

java.lang.reflect

 

java.math

 

java.net

 

java.nio

 

java.nio.channels

 

java.nio.channels.spi

 

java.nio.charset

 

java.nio.charset.spi

 

java.nio.file

 

java.nio.file.attribute

 

java.nio.file.spi

 

java.security

 

java.security.cert

 

java.security.interfaces

 

java.security.spec

 

java.text

 

java.text.spi

 

java.time

 

java.time.chrono

 

java.time.format

 

java.time.temporal

 

java.time.zone

 

java.util

 

java.util.concurrent

 

java.util.concurrent.atomic

 

java.util.concurrent.locks

 

java.util.function

 

java.util.jar

 

java.util.logging

 

java.util.regex

 

java.util.spi

 

java.util.stream

 

java.util.zip

 

javax.net

 

javax.net.ssl

 

javax.script

 

javax.security.auth

 

javax.security.auth.callback

 

javax.security.auth.login

 

javax.security.auth.spi

 

javax.security.auth.x500

 

javax.security.cert

java.rmi

 

java.rmi.activation

 

java.rmi.dgc

 

java.rmi.registry

 

java.rmi.server

 

java.sql

 

javax.rmi.ssl

 

javax.sql

 

javax.transaction

 

javax.transaction.xa

 

javax.xml

 

javax.xml.datatype

 

javax.xml.namespace

 

javax.xml.parsers

 

javax.xml.stream

 

javax.xml.stream.events

 

javax.xml.stream.util

 

javax.xml.transform

 

javax.xml.transform.dom

 

javax.xml.transform.sax

 

javax.xml.transform.stax

 

javax.xml.transform.stream

 

javax.xml.validation

 

javax.xml.xpath

 

org.w3c.dom

 

org.w3c.dom.bootstrap

 

org.w3c.dom.events

 

org.w3c.dom.ls

 

org.w3c.dom.views

 

org.xml.sax

 

org.xml.sax.ext

 

org.xml.sax.helpers

java.lang.instrument

 

java.lang.management

 

java.security.acl

 

java.util.prefs

 

javax.annotation.processing

 

javax.lang.model

 

javax.lang.model.element

 

javax.lang.model.type

 

javax.lang.model.util

 

javax.management

 

javax.management.loading

 

javax.management.modelmbean

 

javax.management.monitor

 

javax.management.openmbean

 

javax.management.relation

 

javax.management.remote

 

javax.management.remote.rmi

 

javax.management.timer

 

javax.naming

 

javax.naming.directory

 

javax.naming.event

 

javax.naming.ldap

 

javax.naming.spi

 

javax.security.auth.kerberos

 

javax.security.sasl

 

javax.sql.rowset

 

javax.sql.rowset.serial

 

javax.sql.rowset.spi

 

javax.tools

 

javax.xml.crypto

 

javax.xml.crypto.dom

 

javax.xml.crypto.dsig

 

javax.xml.crypto.dsig.dom

 

javax.xml.crypto.dsig.keyinfo

 

javax.xml.crypto.dsig.spec

 

org.ietf.jgss

 

How to compile a class using given compact profile?

Syntax

javac -profile {compact1|compact2|compact3} JavaClass

 

Example

javac -profile compact1 App.java

 

App.java

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

public class App {

	public static void main(String args[]) throws IOException {

		try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));) {
			System.out.println("Enter your name");
			String name = br.readLine();

			System.out.println("Hello " + name);
		}

	}
}


Since java.io package is part of compact1 profile, we can use this profile to compile App.java. Execute the command ‘javac -profile compact1 App.java’ to compile App.java using compact1 profile.

$javac -profile compact1 App.java
$ls
App.class	App.java


How to list dependencies in a class file?

Use jdeps tool to list the dependencies in a class file.

 

jdeps App.class

 

This command generate below output.

$jdeps App.class 
App.class -> /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/rt.jar
   <unnamed> (App.class)
      -> java.io                                            
      -> java.lang


You can even get more verbose output using -verbose option.

$jdeps -verbose -P App.class
App.class -> /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/rt.jar (compact1)
   App                                                -> java.io.BufferedReader                             compact1
   App                                                -> java.io.IOException                                compact1
   App                                                -> java.io.InputStream                                compact1
   App                                                -> java.io.InputStreamReader                          compact1
   App                                                -> java.io.PrintStream                                compact1
   App                                                -> java.io.Reader                                     compact1
   App                                                -> java.lang.Object                                   compact1
   App                                                -> java.lang.String                                   compact1
   App                                                -> java.lang.StringBuilder                            compact1
   App                                                -> java.lang.System                                   compact1
   App                                                -> java.lang.Throwable                                compact1


Create smaller Java Platform using jrecreate tool

Download ‘Oracle Java SE Embedded version 8’ from below link.

https://www.oracle.com/java/technologies/java-embedded-java-se-downloads.html

 

Extract the downloaded zip file. You will see ‘ejdk1.8.0/’ folder after extraction.

 

Go to ‘bin’ directory of ejdk1.8.0 folder, you will see jrecreate.sh file.

$ls
jrecreate.bat        jrecreate.config.properties   jrecreate.sh


Execute following command to generate jre with compact1 profile.

 

jrecreate.sh -d ./compact1-jre/ -p compact1

 

Above command generates a folder ‘compact1-jre’ in current directory.

$jrecreate.sh -d ./compact1-jre/ -p compact1
Building JRE using Options {
    ejdk-home: /Users/krishna/Downloads/ejdk1.8.0
    dest: /Users/krishna/Documents/technical-documents/programs/./compact1-jre
    target: linux_arm_vfp_hflt
    vm: minimal
    runtime: compact1 profile
    debug: false
    keep-debug-info: false
    no-compression: false
    dry-run: false
    verbose: false
    extension: []
}


Target JRE Size is 10,513 KB (on disk usage may be greater).

Embedded JRE created successfully

 

Now you can use compact1-jre to ship App.class file. Hopw you enjoyed this tutorial.




Previous                                                    Next                                                    Home