ZOFTINO.COM android and web dev tutorials

Java Set Examples

Java Set is a collections interface. It contains non duplicate elements. Sub interfaces of set are SortedSet and NavigableSet. Implementations of Set are HashSet, EnumSet, LinkedHashSet and TreeSet.

Table of Contents

Set Hierarchy

java set hierarchy

HashSet

HashSet is backed by HashMap instance. It offers same performance for basic operations such as add, remove, size and contains. Time it takes to iterate over HashSet elements is proportional to sum of its size and capacity.

You can instantiate HashSet by using no argument constructor or passing initial capacity or passing initial capacity and load factor to other constructors. Load factor represents the filled percentage of current capacity of the set, used as an indicator to further increase the capacity of set. With default constructor, initial capacity is set to 16 elements and load factor is set to 0.75.

	Set<String> set = new HashSet<>();
	Set<Integer> intSet = new HashSet<>(100);
	Set<Long> longSet = new HashSet<Long>(100, (float) 0.80);

HashSet can also be instantiated using other collection objects.

	List<String> stores = new ArrayList<>();
	stores.add("amazon");
	stores.add("walmart");
	stores.add("amazon");
	
	Set<String> storeSet = new HashSet<>(stores);
	System.out.println(storeSet);

Output

[amazon, walmart]

It permits null value. If you add duplicate elements to a set, it just simply retains only one value.

	Set<String> set = new HashSet<>();

	set.add("2");
	set.add("2");
	set.add(null);
	set.add(null);
	System.out.println(set);

Output

[null, 2]

Elements stored in HashSet are not ordered based on a particular criterion. Following examples shows two sets with same elements but different initial capacity and order of the elements.

	Set<String> set = new HashSet<>(100);
	set.add("2");
	set.add("sa");
	set.add("sb");
	set.add("3");
	set.add("sc");
	System.out.println(set);


	set = new HashSet<>(1);
	set.add("2");
	set.add("sa");
	set.add("sb");
	set.add("3");
	set.add("sc");
	System.out.println(set);

Output

[2, 3, sa, sb, sc]
[sc, 2, 3, sa, sb]

HashSet Examples

Following example shows adding and removing elements, knowing size, clearing has set and checking for emptiness and an object existence.

	Set<String> set = new HashSet<>();
	
	if(set.isEmpty()) {
		System.out.println("empty set");
	}
	
	set.add("android");	
	set.add("ios");	
	System.out.println("size "+set.size());
	
	if(set.contains("android"))
		System.out.println("contains android");
	
	set.remove("android");
	System.out.println("after remove size "+set.size());
	
	set.clear();
	System.out.println("after clear size "+set.size());

Output

empty set
size 2
contains android
after remove size 1
after clear size 0

Traversing Elements Iterator

You can traverse through HashSet or any collection by obtaining iterator object of it. You can get element by calling next() method and remove element by calling remove() method.

	Set<String> set = new HashSet<>();

	set.add("coupons");
	set.add("deals");
	set.add("sale");
	set.add("cashback");
	
	Iterator<String> iterator = set.iterator();
	while(iterator.hasNext()) {		
		String offer = iterator.next();
		System.out.println(offer);
		
		if("sale".equals(offer))
			iterator.remove();
	}
	System.out.println(set);
sale
coupons
deals
cashback
content after remove call on iterator
[coupons, deals, cashback]

AddAll Example

To add collection of elements to set, you can use addAll method.

	Set<String> wireless = new HashSet<>();
	
	List<String> items = new ArrayList<>();
	items.add("phone");
	items.add("plan");
	items.add("features");

	System.out.println("set size before addAll "+wireless.size());
	
	wireless.addAll(items);
	
	System.out.println("set size after addAll "+wireless.size());
set size before addAll 0
set size after addAll 3

RemoveAll Example

You can use removeAll method to remove collection of items from the set.

	Set<String> categories = new HashSet<>();
	categories.add("electronics");
	categories.add("mobiles");
	categories.add("fashion");
	categories.add("tablet");
	categories.add("appliance");
	categories.add("travel");
	
	List<String> electronics = new ArrayList<>();
	electronics.add("electronics");
	electronics.add("mobiles");
	electronics.add("tablet");
	
	System.out.println("set size before removeAll "+categories.size());
	
	categories.removeAll(electronics);
	
	System.out.println("set size after removeAll "+categories.size());

Output

set size before removeAll 6
set size after removeAll 3

ContainsAll and RetainAll Example

You can check whether a set contains all the elements of a give collection using containsAll methods. Method retainAll removes all the elements from the set except the elements of given collection.

	Set<String> brands = new HashSet<>();
	brands.add("apple");
	brands.add("samsung");
	brands.add("moto");
	brands.add("lg");
	
	List<String> brandsExtra = new ArrayList<>();
	brandsExtra.add("samsung");
	brandsExtra.add("lg");
	
	if(brands.containsAll(brandsExtra)) {
		System.out.println("set contains all the elements of list");
	}
	
	brands.retainAll(brandsExtra);
	System.out.println(brands);
set contains all the elements of list
[samsung, lg]

RemoveIf Example

Elements of a set can be removed based on a condition defined in the Predicate object which is passed to removeIf method as an argument. Each element of the set is passed to test() method of the predicate. Elements are removed if test() returns true for them.

	Set<String> offers = new HashSet<>();
	offers.add("upto 5% cashback on fashion");
	offers.add("flat 50% off on shoe");
	offers.add("upto 70% off on bags");
	offers.add("2% cashback on mobiles");
	
	offers.removeIf( new Predicate<String>() {
		@Override
		public boolean test(String t) {
			//remove cashback offers
			if(t.contains("cashback")) {
				return true;
			}
			return false;
		}			
	});
	
	System.out.println(offers);

Output

[upto 70% off on bags, flat 50% off on shoe]

ToArray Example

Set can be converted into array using toArray method.

	Set<Integer> price = new HashSet<>();
	price.add(200);
	price.add(197);
	price.add(234);
	
	//array of objects
	Object priceArray[] = price.toArray();
	
	//array of specific type
	Integer prices[] = new Integer[price.size()];
	price.toArray(prices);
	
	for(int pri : prices) {
		System.out.println(pri);
	}

Output

197
200
234

Stream Example

Set or all the collections can be converted using stream() or parallelStream() method into a Stream object which emits all the elements of set. You can apply operations that stream provides on the elements to filter, modify or perform certain action. In the following example, map operation is used to convert all the elements of hash set into lowercase, then filter is applied to filter elements and finally forEach operation prints the remaining elements.

	Set<String> deals = new HashSet<>();
	deals.add("upto 5% cashback on fashion");
	deals.add("flat 50% off on shoe");
	deals.add("upto 70% off on bags");
	deals.add("2% cashback on mobiles");

	deals.stream().map(s -> {
		return s.toLowerCase();
	}).filter(s -> {
		return s.contains("cashback");
	}).forEach(s -> System.out.println(s));

Output

upto 5% cashback on fashion
2% cashback on mobiles

Spliterator Example

You can obtain spliterator object from collections by calling spliterator() method. Spliterator allows you to split collection into multiple collections and perform operations on each collection separately on different threads. Spliterator can be split into two using trySplit() method. Spliterator allows you perform action on each element using forEachRemaining() method.

	Set<String> brands = new HashSet<>();
	brands.add("apple");
	brands.add("samsung");
	brands.add("moto");
	brands.add("lg");

	Spliterator<String> split = brands.spliterator();
	Spliterator<String> splitTwo = split.trySplit();

	new Thread(new Runnable() {
		@Override
		public void run() {
			split.forEachRemaining(s -> {
				System.out.println("split : "+s);
			});
		}
	}).start();

	splitTwo.forEachRemaining(s -> {
		System.out.println("split two : "+s);
	});

Output

split : lg
split two : apple
split two : samsung
split : moto

Concurrent Access

If hash set or any other collection implementation is concurrently shared among multiple threads with reads and at least one write to it, it needs to be synchronized. Otherwise, it will lead to unexpected results due to data inconsistency. All the operations of collections are not synchronized. You can use synchronizedSet static method of Collections class to convert set into synchronized set.

	Set<String> set = new HashSet<>(10);
	Set threadSafeSet = Collections.synchronizedSet(set);

When iterating over set, if other threads modify the set, it will throw ConcurrentModificationException. This behavior of iterator is called fail-fast. Following example throws the exception.

	Set<String> set1 = new HashSet<>(10);
	Set<String> set = Collections.synchronizedSet(set1);		
	
	set.add("2");
	set.add("sa");
	set.add("sb");
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			for(int i = 0; i<5; i++) {
				set.add("sc"+i);
			}				
		}			
	}).start();

	Iterator<String> i = set.iterator();
	while(i.hasNext()) {
		System.out.println(i.next());
	}

This can be prevented using synchronized block.

	synchronized(set) {
		Iterator<String> i = set.iterator();
		while(i.hasNext()) {
			System.out.println(i.next());
		}
	}

For performance in the context of multiple threads accessing collections, you can use collections like ConcurrentHashMap provided in concurrency framework.

To create concurrent hash set, you can use ConcurrentHashMap and call newKeySet static method as shown in the following example.

	Set<String> concurrentHashSet = ConcurrentHashMap.newKeySet();
	
	concurrentHashSet.add("sears");
	concurrentHashSet.add("macys");
	
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			for(int i = 0; i<5; i++) {
				concurrentHashSet.add("store-"+i);
			}				
		}			
	}).start();


	Iterator<String> i = concurrentHashSet.iterator();
	while(i.hasNext()) {
		System.out.println(i.next());
	}

	try {
		Thread.sleep(500);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println(concurrentHashSet);

LinkedHashSet

LinkedHashSet extends HashSet. The difference between LinkedHashSet and HashSet is that LinkedHashSet maintains order of elements in which they are inserted into it. LinkedHashSet supports all the methods provided by HashSet.

	Set<String> set = new LinkedHashSet<>(100);
	set.add("2");
	set.add("sa");
	set.add("sb");
	set.add("3");
	set.add("sc");
	System.out.println(set);
	
	set = new LinkedHashSet<>(10);
	set.add("2");
	set.add("sa");
	set.add("sb");
	set.add("3");
	set.add("sc");
	System.out.println(set);

Output

[2, sa, sb, 3, sc]
[2, sa, sb, 3, sc]

TreeSet

TreeSet implements NavigableSet interface and extends AbstractSet. Order of elements is maintained using their natural order or by using the provided comparator. TreeSet is navigable both ascending and descending orders. Similar to HashSet, TreeSet operations and iterator should be accessed as explained in the concurrent access section.

TreeSet can be instantiated using no argument constructor which sorts the elements using natural order.

	Set<Integer> price = new TreeSet<>();
	price.add(123);
	price.add(229);
	price.add(34);
	
	System.out.println(price);

Output

[34, 123, 229]

You can pass comparator to its constructors to order the elements based on the comparator. Following example shows instantiating TreeSet passing a comparator which makes it sort its elements in descending order.

	Comparator<Integer> comparator = new Comparator<Integer>() {
		@Override
		public int compare(Integer num, Integer numTwo) {
			if(num > numTwo) {
				return -1;
			}else {
				return 1;
			}
		}			
	};
	
	Set<Integer> price = new TreeSet<>(comparator);
	price.add(123);
	price.add(229);
	price.add(34);
	
	System.out.println(price);

Output

[229, 123, 34]

TreeSet Methods with Examples

Method ceiling() returns least element which is greater than or equals to the give element.

	NavigableSet<Integer> price = new TreeSet<>();
	price.add(123);
	price.add(64);
	price.add(229);
	price.add(340);
	price.add(34);
	
	System.out.println(price.ceiling(120));

Output

123

Similarly floor() returns greatest element which is less than or equals to the given number.

System.out.println(price.floor(120));

Output

64

Methods higher() returns least element which is strictly greater than the given element and lower() returns greatest element which is strictly less than the given element.

	NavigableSet<Integer> price = new TreeSet<>();
	price.add(123);
	price.add(64);
	price.add(120);
	price.add(229);
	price.add(340);
	price.add(34);
	
	System.out.println("ceiling: "+price.ceiling(120));		
	System.out.println("floor: "+price.floor(120));
	
	System.out.println("higher: "+price.higher(120));		
	System.out.println("lower: "+price.lower(120));

Output

ceiling: 120
floor: 120
higher: 123
lower: 64

Methods first and pollFirst return first element and methods last and pollLast return last element. Methods pollFirst and pollLast don’t throw exception and return null if set is empty.

		System.out.println("first: "+price.first());		
		System.out.println("last: "+price.last());

Output

first: 34
last: 340

You can iterate over tree set in reverse order using iterator object returned by descendingIterator() method. You can create a set which is a view of source set and contains elements in reverse order by calling descendingSet() on the source set.

	NavigableSet<String> brands = new TreeSet<>();
	brands.add("polo");
	brands.add("tommy");
	brands.add("boss");
	brands.add("nautica");
	
	System.out.println(brands);
	
	System.out.println("reverse order set: "+brands.descendingSet());

Output

[boss, nautica, polo, tommy]
reverse order set: [tommy, polo, nautica, boss]

You can create a set which is view of source set and contains elements greater than the given element by calling tailSet() method on the source set.

In the same way, you can create a set which contains element less than the given element by calling headSet() method on source set and a set which contains a range of elements which exist between the two given elements by calling subSet() method.

		NavigableSet<Integer> price = new TreeSet<>();
		price.add(434);
		price.add(123);
		price.add(64);
		price.add(120);
		price.add(229);
		price.add(340);
		price.add(34);
		price.add(22);
		
		System.out.println("head set: "+price.headSet(64));
		System.out.println("tail set: "+price.tailSet(64));
		System.out.println("sub set: " +price.subSet(64, 229));

Output

head set: [22, 34]
tail set: [64, 120, 123, 229, 340, 434]
sub set: [64, 120, 123]

EnumSet

EnumSet is used with enum elements. It is an abstract class which extends AbstractSet. Instance of EnumSet can be created using of, range, noneOf, allOf and complementOf static methods of EnumSet. It allows you to utilize set operations on enum.

enum Offer {
	COUPON, CASHBACK, DEAL, SALE
}
public class CollectionsExamples {

	public static void main(String[] args) {		

		Set<Offer> offer= EnumSet.allOf(Offer.class);
		System.out.println("allOf: "+offer);
		
		offer= EnumSet.of(Offer.CASHBACK, Offer.DEAL);
		System.out.println("of: "+offer);
		
		offer= EnumSet.range(Offer.CASHBACK, Offer.SALE);
		System.out.println("range: "+offer);
	}
}

Output

allOf: [COUPON, CASHBACK, DEAL, SALE]
of: [CASHBACK, DEAL]
range: [CASHBACK, DEAL, SALE]