Skip to content
This repository has been archived by the owner on Jan 4, 2020. It is now read-only.

Some collection interfaces and implementations, mainly intended for clear-cut API design

License

Notifications You must be signed in to change notification settings

markenwerk/java-commons-collections

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Some collection interfaces and implementations

Build Status Coverage Status Dependency Status Maven Central Java SE 6 MIT License

Overview

This is a collection of some collection interfaces and implementations, mainly intended for clear-cut API design:

This library is hosted in the Maven Central Repository. You can use it with the following coordinates:

<dependency>
	<groupId>net.markenwerk</groupId>
	<artifactId>commons-collections</artifactId>
	<version>1.0.0</version>
</dependency>

Consult the usage description and Javadoc for further information.

Motivation

This library provides collections for clear-cut API design. Most libraries just use JAVA's collection API. Although this has the important advantage, that the API is well known and understood, it is mostly intended as a general purpose API and not for clear-cut API. A clear-cut API should convey as much usage description as possible through the type system and names of public methods, interfaces and classes. if, for example, an API allows a read-only access to one of its properties, there should only be a getter-method for that property and no setter-method. If the API would have a setter-method in such a scenario, it would need to throw an UnsupportedOperationException, to protect its internal state, should the method be invoked by the API user and inform the API user about this fact in the API documentation. Not to include an unwanted setter in an APi is easy, but if the API designer wants to allow a read-only access to a collection, he has several options (All of which we observed in the public APIs of several libraries):

  1. Include a getter-method for an unmodifiable JAVA collections to the API interface, i.e. by returning a Collections.unmodifiableCollection() and convey this fact in the API documentation. This is undesirable, because the API user receives a Collection object that is going to throw exception at runtime, if the API user doesn't read the API documentation carefully.
  2. Add methods that mimic the desired subset of the behavior of the JAVA collection class to the API interface, i.e. by adding add(), addAll(), ... instead of a getter-method for an unmodifiable JAVA collection. This is undesirable because it pollutes the API interface with a lot of methods, especially if the API interface has more than one such collection (and the method names need to be suffixed accordingly), it will easily become inconsistent, complicate testing and generally defeats the purpose of OOP.
  3. Add just the minimum subset of methods that mimic the behavior of a collection class, i.e. by adding add(), ..., but no convenience methods like addAll(). This has all the disadvantages of the previous option, but with added inconvenience.

This is where this library comes in. It provides interfaces for collections with read-only-access, write-only-access and for common data-structures. If, for example, an API wants to publish a stack, it can't use JAVA collections, because ther is no pure stack. A List and even a Stack offer a lot of methods, that allow "un-stack-like" access.

Interfaces

Sink

The Sink interface should be used by components that allow a write-only-access.

A Sink must implement the following methods:

public Sink<Payload> add(Payload payload);

public Sink<Payload> addAll(Payload... payloads);

public Sink<Payload> addAll(Iterable<? extends Payload> payloads);

A Sink is forbidden to reveal information about the content of an underlying component through its hashCode-, equals()- or toString()-methods.

This library provides AbstractSink as a base implementation and CollectionSink, HandlerSink, SequenceSink and StackSink as ready-to-use implementations that are backed by the corresponding components.

Source

The Source interface should be used by components that allow a read-only-access.

A Source must, in essence, implement the following methods:

public boolean isEmpty();

public int size();

public Payload getFirst() throws NoSuchElementException;

public boolean contains(Object reference);

There are several other methods that can be used to query or filter the Source using a reference object or a Predicate.

The IndexedSource interface should be used by components that allow a read-only-access to a linear data-structure.

An IndexedSource is a Source that must, in essence, implement the following additional methods:

public Payload get(int index) throws IndexOutOfBoundsException;

public boolean isFirst(Payload payload) throws NoSuchElementException;

public boolean isLast(Payload payload) throws NoSuchElementException;

public Payload getLast() throws NoSuchElementException;

public Optional<Integer> firstIndexOf(Payload payload);

public Optional<Integer> lastIndexOf(Payload payload);

There are several other methods that can be used to query or filter the IndexedSource using a reference object or a Predicate.

This library provides AbstractSource and AbstractIndexedSource as a base implementation and ArraySource, CollectionSource, EmptySource, ListSource, MapKeySource, MapValueSource, ObjectSource and OptionalSource as ready-to-use implementations that are backed by the corresponding components.

Stack

The Stack interface should be used by components that need a pure stack.

A Stack is a Source that must, in essence, implement the following additional methods:

public Stack<Payload> push(Payload payload);

public Stack<Payload> pushAll(Payload... payloads);

public Payload pop() throws NoSuchElementException;

public Source<Payload> popAll(int number) throws IllegalArgumentException;

public Payload get(int index) throws IndexOutOfBoundsException;

public Payload getFirst() throws NoSuchElementException;

public replace(Payload payload) NoSuchElementException;

public Source<Payload> clear();

public ProtectedIterator<Payload> iterator();

There are several other methods that can be used to query or filter the Stack using a reference object or a Predicate.

This library provides AbstractStack as a base implementation and LinkedStack as a ready-to-use implementation.

Sequence

The Sequence interface should be used by components that need a pure linear data-structure.

A Sequence is an IndexedSource that must, in essence, implement the following additional methods:

public Sequence<Payload> insert(int index, Payload payload) throws IndexOutOfBoundsException;

public Sequence<Payload> insertAll(int index, Payload... payloads) throws IndexOutOfBoundsException;

public Sequence<Payload> prepend(Payload payload);

public Sequence<Payload> prependAll(Payload... payloads);

public Sequence<Payload> append(Payload payload);

public Sequence<Payload> appendAll(Payload... payloads);

public Payload remove(int index) throws IndexOutOfBoundsException;

public Payload removeFirst() throws NoSuchElementException;

public Payload removeLast() throws NoSuchElementException;

public Source<Payload> removeAll(Payload reference);

public Source<Payload> retainAll(Payload reference);

public Source<Payload> clear();

public Payload replace(int index, Payload replacement) IndexOutOfBoundsException;

There are several other methods that can be used to query or filter the Sequence using a reference object or a Predicate.

This library provides AbstractSequence as a base implementation and Listsequence as a ready-to-use implementation.

About

Some collection interfaces and implementations, mainly intended for clear-cut API design

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages