Comparing Unmodifiable Sets: A Comprehensive Guide

Can We Use To Compare Two Collections.unmodifiableset? Absolutely. Collections.unmodifiableSet in Java provides a way to create read-only sets, and understanding how to compare these immutable structures is crucial for robust and reliable code. This guide on COMPARE.EDU.VN dives deep into the methods, considerations, and best practices for effectively comparing unmodifiable sets, ensuring you can make informed decisions when working with immutable data structures, offering comprehensive set analysis and evaluation techniques.

1. Understanding Unmodifiable Sets

Before diving into comparisons, it’s essential to understand what unmodifiable sets are and why they are used.

1.1 What is an Unmodifiable Set?

An unmodifiable set is a set that cannot be modified after its creation. Any attempt to add, remove, or clear elements from such a set will result in an UnsupportedOperationException. The java.util.Collections class provides methods to create unmodifiable views of various collections, including sets.

1.2 Creating Unmodifiable Sets

The primary method for creating an unmodifiable set is Collections.unmodifiableSet(Set<? extends T> s). This method returns an unmodifiable view of the specified set.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class UnmodifiableSetExample {
    public static void main(String[] args) {
        Set<String> originalSet = new HashSet<>();
        originalSet.add("Apple");
        originalSet.add("Banana");
        originalSet.add("Cherry");

        Set<String> unmodifiableSet = Collections.unmodifiableSet(originalSet);

        // Attempting to modify the unmodifiable set will throw an exception
        try {
            unmodifiableSet.add("Date");
        } catch (UnsupportedOperationException e) {
            System.out.println("Exception: " + e.getMessage());
        }

        System.out.println("Original Set: " + originalSet);
        System.out.println("Unmodifiable Set: " + unmodifiableSet);
    }
}

In this example, unmodifiableSet is an unmodifiable view of originalSet. Any attempt to modify unmodifiableSet will throw an UnsupportedOperationException.

1.3 Why Use Unmodifiable Sets?

  1. Immutability: Unmodifiable sets ensure that the data remains constant, preventing accidental modifications.
  2. Thread Safety: Immutable objects are inherently thread-safe, as they cannot be modified by multiple threads concurrently.
  3. Defensive Programming: Using unmodifiable sets helps in writing more robust code by preventing unintended side effects.
  4. Data Integrity: Unmodifiable sets guarantee the integrity of the data, ensuring that it remains consistent throughout the application.

2. Methods for Comparing Unmodifiable Sets

Several methods can be used to compare unmodifiable sets, each with its own advantages and use cases.

2.1 Using the equals() Method

The most straightforward way to compare two sets is by using the equals() method. This method checks if two sets contain the same elements, regardless of their order.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSets {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add("Apple");
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

In this example, unmodifiableSet1 and unmodifiableSet2 are considered equal because they contain the same elements, even though the order is different.

2.2 Comparing with hashCode()

The hashCode() method can be used to quickly check if two sets are potentially equal. If two sets have different hash codes, they are definitely not equal. However, if they have the same hash code, it does not guarantee that they are equal; you still need to use the equals() method to confirm.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSetsHashCode {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add("Apple");
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        int hashCode1 = unmodifiableSet1.hashCode();
        int hashCode2 = unmodifiableSet2.hashCode();

        System.out.println("Set 1: " + unmodifiableSet1 + ", Hash Code: " + hashCode1);
        System.out.println("Set 2: " + unmodifiableSet2 + ", Hash Code: " + hashCode2);

        if (hashCode1 == hashCode2) {
            boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);
            System.out.println("Hash codes are equal. Are the sets equal? " + areEqual);
        } else {
            System.out.println("Hash codes are different. Sets are not equal.");
        }
    }
}

Using hashCode() can provide a performance optimization by quickly ruling out non-equal sets.

2.3 Using Iterators to Compare Elements

You can also compare two unmodifiable sets by iterating through their elements and comparing them individually. This approach is more verbose but can be useful when you need to perform additional operations during the comparison.

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class CompareUnmodifiableSetsIterator {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add("Apple");
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = compareSetsUsingIterator(unmodifiableSet1, unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }

    public static <T> boolean compareSetsUsingIterator(Set<T> set1, Set<T> set2) {
        if (set1.size() != set2.size()) {
            return false;
        }

        Iterator<T> iterator1 = set1.iterator();
        Iterator<T> iterator2 = set2.iterator();

        while (iterator1.hasNext()) {
            if (!set2.contains(iterator1.next())) {
                return false;
            }
        }

        return true;
    }
}

This method first checks if the sizes of the sets are equal. If not, the sets are not equal. Then, it iterates through the first set and checks if each element is present in the second set.

2.4: Using Streams for Comparison

Java Streams provide a concise and functional way to compare sets. You can convert the sets to streams and use operations like allMatch and contains to check for equality.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSetsStreams {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add("Apple");
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = compareSetsUsingStreams(unmodifiableSet1, unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }

    public static <T> boolean compareSetsUsingStreams(Set<T> set1, Set<T> set2) {
        if (set1.size() != set2.size()) {
            return false;
        }

        return set1.stream().allMatch(set2::contains);
    }
}

This method checks if all elements of set1 are contained in set2. If the sizes are different, it immediately returns false. This approach is both readable and efficient.

3. Considerations When Comparing Unmodifiable Sets

When comparing unmodifiable sets, there are several factors to consider to ensure accurate and efficient comparisons.

3.1 Null Handling

When comparing sets, it’s important to handle null values properly. If a set contains null elements, the comparison logic should account for this.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSetsNull {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add(null);
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add(null);
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

In this example, both sets contain a null element. The equals() method correctly handles null values, ensuring that the sets are compared accurately.

3.2 Performance

The performance of set comparisons can vary depending on the size of the sets and the comparison method used. For large sets, using hashCode() to quickly rule out non-equal sets can improve performance. Additionally, using streams can provide a more efficient way to compare sets due to their ability to parallelize operations.

3.3 Type Compatibility

When comparing sets, ensure that the elements in the sets are type-compatible. If the sets contain elements of different types, the comparison logic should handle this gracefully to avoid ClassCastException errors.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSetsType {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<Integer> set2 = new HashSet<>();
        set2.add(1);
        set2.add(2);
        set2.add(3);

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<Integer> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

In this example, unmodifiableSet1 contains strings, while unmodifiableSet2 contains integers. The equals() method returns false because the sets contain different elements.

3.4 Deep vs. Shallow Comparison

When comparing sets containing complex objects, it’s important to consider whether you need a deep or shallow comparison. A shallow comparison checks if the object references are the same, while a deep comparison checks if the contents of the objects are the same.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

class Fruit {
    private String name;

    public Fruit(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Fruit fruit = (Fruit) obj;
        return name.equals(fruit.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + ''' +
                '}';
    }
}

public class CompareUnmodifiableSetsDeep {
    public static void main(String[] args) {
        Set<Fruit> set1 = new HashSet<>();
        set1.add(new Fruit("Apple"));
        set1.add(new Fruit("Banana"));
        set1.add(new Fruit("Cherry"));

        Set<Fruit> set2 = new HashSet<>();
        set2.add(new Fruit("Banana"));
        set2.add(new Fruit("Apple"));
        set2.add(new Fruit("Cherry"));

        Set<Fruit> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<Fruit> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

In this example, the Fruit class overrides the equals() and hashCode() methods to perform a deep comparison based on the name field.

4. Best Practices for Comparing Unmodifiable Sets

Following best practices ensures that your comparisons are accurate, efficient, and maintainable.

4.1 Use the equals() Method for Simple Comparisons

For most cases, the equals() method provides a simple and reliable way to compare unmodifiable sets. It handles null values and performs a deep comparison when necessary.

4.2 Optimize Performance with hashCode()

For large sets, use the hashCode() method to quickly rule out non-equal sets before performing a full comparison with equals().

4.3 Use Streams for Concise and Efficient Comparisons

Java Streams provide a concise and efficient way to compare sets, especially when combined with operations like allMatch and contains.

4.4 Handle Null Values Properly

Always consider the possibility of null values in your sets and ensure that your comparison logic handles them correctly.

4.5 Consider Deep vs. Shallow Comparison

When comparing sets containing complex objects, determine whether you need a deep or shallow comparison and implement the appropriate equals() and hashCode() methods.

5. Practical Examples of Comparing Unmodifiable Sets

To illustrate the practical application of comparing unmodifiable sets, let’s consider a few real-world examples.

5.1 Comparing Sets of User Roles

Suppose you have a system where users can have multiple roles, and you want to compare the roles assigned to different users.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUserRoles {
    public static void main(String[] args) {
        Set<String> roles1 = new HashSet<>();
        roles1.add("Admin");
        roles1.add("Editor");
        roles1.add("Viewer");

        Set<String> roles2 = new HashSet<>();
        roles2.add("Editor");
        roles2.add("Admin");
        roles2.add("Viewer");

        Set<String> unmodifiableRoles1 = Collections.unmodifiableSet(roles1);
        Set<String> unmodifiableRoles2 = Collections.unmodifiableSet(roles2);

        boolean areEqual = unmodifiableRoles1.equals(unmodifiableRoles2);

        System.out.println("User 1 Roles: " + unmodifiableRoles1);
        System.out.println("User 2 Roles: " + unmodifiableRoles2);
        System.out.println("Do users have the same roles? " + areEqual);
    }
}

In this example, unmodifiableRoles1 and unmodifiableRoles2 represent the roles assigned to two different users. The equals() method is used to determine if the users have the same roles.

5.2 Comparing Sets of Product Categories

Suppose you have an e-commerce application where products can belong to multiple categories, and you want to compare the categories assigned to different products.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareProductCategories {
    public static void main(String[] args) {
        Set<String> categories1 = new HashSet<>();
        categories1.add("Electronics");
        categories1.add("Home Appliances");
        categories1.add("Mobile");

        Set<String> categories2 = new HashSet<>();
        categories2.add("Home Appliances");
        categories2.add("Electronics");
        categories2.add("Mobile");

        Set<String> unmodifiableCategories1 = Collections.unmodifiableSet(categories1);
        Set<String> unmodifiableCategories2 = Collections.unmodifiableSet(categories2);

        boolean areEqual = unmodifiableCategories1.equals(unmodifiableCategories2);

        System.out.println("Product 1 Categories: " + unmodifiableCategories1);
        System.out.println("Product 2 Categories: " + unmodifiableCategories2);
        System.out.println("Do products have the same categories? " + areEqual);
    }
}

In this example, unmodifiableCategories1 and unmodifiableCategories2 represent the categories assigned to two different products. The equals() method is used to determine if the products belong to the same categories.

5.3 Comparing Sets of Permissions

In a system with access control, comparing sets of permissions is crucial to determine if a user has the necessary access rights.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class ComparePermissions {
    public static void main(String[] args) {
        Set<String> permissions1 = new HashSet<>();
        permissions1.add("Read");
        permissions1.add("Write");
        permissions1.add("Execute");

        Set<String> permissions2 = new HashSet<>();
        permissions2.add("Write");
        permissions2.add("Read");
        permissions2.add("Execute");

        Set<String> unmodifiablePermissions1 = Collections.unmodifiableSet(permissions1);
        Set<String> unmodifiablePermissions2 = Collections.unmodifiableSet(permissions2);

        boolean areEqual = unmodifiablePermissions1.equals(unmodifiablePermissions2);

        System.out.println("User 1 Permissions: " + unmodifiablePermissions1);
        System.out.println("User 2 Permissions: " + unmodifiablePermissions2);
        System.out.println("Do users have the same permissions? " + areEqual);
    }
}

Here, unmodifiablePermissions1 and unmodifiablePermissions2 represent the permissions assigned to two different users. The equals() method checks if the users have the same permissions.

6. Advanced Techniques for Comparing Unmodifiable Sets

For more complex scenarios, advanced techniques can be employed to compare unmodifiable sets.

6.1 Using Custom Comparators

When the default comparison logic is not sufficient, you can use custom comparators to define your own comparison rules.

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

class CustomStringComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareToIgnoreCase(s2);
    }
}

public class CompareUnmodifiableSetsCustomComparator {
    public static void main(String[] args) {
        Set<String> set1 = new TreeSet<>(new CustomStringComparator());
        set1.add("Apple");
        set1.add("banana");
        set1.add("Cherry");

        Set<String> set2 = new TreeSet<>(new CustomStringComparator());
        set2.add("Banana");
        set2.add("apple");
        set2.add("CHERRY");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = unmodifiableSet1.equals(unmodifiableSet2);

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

In this example, a custom comparator CustomStringComparator is used to compare strings case-insensitively.

6.2 Using Libraries for Complex Comparisons

Libraries like Guava and Apache Commons Collections provide additional utility methods for comparing collections, including sets.

import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompareUnmodifiableSetsGuava {
    public static void main(String[] args) {
        Set<String> set1 = new HashSet<>();
        set1.add("Apple");
        set1.add("Banana");
        set1.add("Cherry");

        Set<String> set2 = new HashSet<>();
        set2.add("Banana");
        set2.add("Apple");
        set2.add("Cherry");

        Set<String> unmodifiableSet1 = Collections.unmodifiableSet(set1);
        Set<String> unmodifiableSet2 = Collections.unmodifiableSet(set2);

        boolean areEqual = Sets.difference(unmodifiableSet1, unmodifiableSet2).isEmpty() &&
                Sets.difference(unmodifiableSet2, unmodifiableSet1).isEmpty();

        System.out.println("Set 1: " + unmodifiableSet1);
        System.out.println("Set 2: " + unmodifiableSet2);
        System.out.println("Are the sets equal? " + areEqual);
    }
}

This example uses the Guava library to check if the sets are equal by verifying that the difference between them is empty.

7. Common Pitfalls to Avoid

When comparing unmodifiable sets, there are several common pitfalls to avoid.

7.1 Modifying the Original Set

If you modify the original set after creating an unmodifiable view, the unmodifiable set will reflect those changes, which can lead to unexpected behavior during comparisons.

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class UnmodifiableSetModification {
    public static void main(String[] args) {
        Set<String> originalSet = new HashSet<>();
        originalSet.add("Apple");
        originalSet.add("Banana");
        originalSet.add("Cherry");

        Set<String> unmodifiableSet = Collections.unmodifiableSet(originalSet);

        originalSet.add("Date"); // Modifying the original set

        System.out.println("Original Set: " + originalSet);
        System.out.println("Unmodifiable Set: " + unmodifiableSet);
    }
}

In this example, modifying originalSet after creating unmodifiableSet will also change unmodifiableSet.

7.2 Incorrectly Implementing equals() and hashCode()

If you are comparing sets containing custom objects, make sure to implement the equals() and hashCode() methods correctly to ensure accurate comparisons.

7.3 Ignoring Null Values

Failing to handle null values properly can lead to NullPointerException errors or incorrect comparison results.

7.4 Using Inefficient Comparison Methods

Using inefficient comparison methods, such as iterating through large sets, can degrade performance. Consider using hashCode() and streams to optimize comparisons.

8. Summary of Comparison Techniques

To summarize, here’s a table comparing the different techniques for comparing unmodifiable sets:

Method Description Pros Cons Use Case
equals() Checks if two sets contain the same elements. Simple, reliable, handles null values. Can be slow for large sets. Most common cases, simple comparisons.
hashCode() Checks if two sets have the same hash code. Quick check to rule out non-equal sets. Requires additional equals() check, doesn’t guarantee equality. Large sets, performance optimization.
Iterators Iterates through elements and compares them individually. Allows additional operations during comparison. More verbose, can be less efficient. When additional operations are needed during comparison.
Streams Converts sets to streams and uses operations like allMatch. Concise, efficient, can be parallelized. Requires Java 8 or later. Modern Java applications, efficient comparisons.
Custom Comparators Defines custom comparison rules using a Comparator. Allows flexible comparison logic. Requires implementing a custom comparator. When default comparison logic is not sufficient.
Libraries (e.g., Guava) Provides additional utility methods for comparing collections. Offers additional functionality, can simplify complex comparisons. Requires adding external dependencies. Complex comparisons, leveraging external libraries.

9. Frequently Asked Questions (FAQ)

Q1: Can I modify an unmodifiable set?

No, you cannot modify an unmodifiable set. Any attempt to add, remove, or clear elements will result in an UnsupportedOperationException.

Q2: How do I create an unmodifiable set?

You can create an unmodifiable set using the Collections.unmodifiableSet(Set<? extends T> s) method.

Q3: What happens if I modify the original set after creating an unmodifiable view?

The unmodifiable set will reflect the changes made to the original set.

Q4: How do I compare two unmodifiable sets for equality?

You can use the equals() method to compare two unmodifiable sets for equality.

Q5: Can I use hashCode() to compare unmodifiable sets?

Yes, you can use hashCode() to quickly check if two sets are potentially equal. If the hash codes are different, the sets are not equal. If the hash codes are the same, you still need to use equals() to confirm.

Q6: How do I handle null values when comparing unmodifiable sets?

Ensure that your comparison logic properly handles null values to avoid NullPointerException errors or incorrect comparison results.

Q7: What is a deep comparison?

A deep comparison checks if the contents of the objects in the sets are the same, as opposed to a shallow comparison, which checks if the object references are the same.

Q8: Can I use custom comparators to compare unmodifiable sets?

Yes, you can use custom comparators to define your own comparison rules when the default comparison logic is not sufficient.

Q9: Are unmodifiable sets thread-safe?

Yes, unmodifiable sets are inherently thread-safe because they cannot be modified after creation.

Q10: What are the benefits of using unmodifiable sets?

The benefits include immutability, thread safety, defensive programming, and data integrity.

10. Conclusion

Comparing unmodifiable sets in Java requires a thorough understanding of the available methods, considerations, and best practices. By using the equals() method, optimizing performance with hashCode(), leveraging streams, handling null values properly, and considering deep vs. shallow comparisons, you can ensure accurate and efficient comparisons. Whether you are comparing sets of user roles, product categories, or permissions, the techniques outlined in this guide will help you write robust and reliable code.

Need more assistance with comparing different data structures or making informed decisions? Visit COMPARE.EDU.VN at 333 Comparison Plaza, Choice City, CA 90210, United States. Contact us via Whatsapp at +1 (626) 555-9090 or explore our website compare.edu.vn for comprehensive comparisons and expert insights.

In this image, the focus is on data structures, specifically how they relate to efficient coding practices. The visual aims to highlight the importance of choosing the right data structure to optimize code performance and efficiency.

This image represents an unmodifiable set containing various data elements, emphasizing the concept of immutability in data structures. It visually demonstrates a collection where elements cannot be altered after creation.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *