From f51b476c04cd6bdf24c31b5a9872af191eeb97e6 Mon Sep 17 00:00:00 2001 From: Diego Leonardo Urban Date: Fri, 6 Nov 2026 17:00:48 +0100 Subject: [PATCH 1/3] Document the data-structure API with complete Javadoc Co-Authored-By: Claude Opus 5.5 --- .../algorithms/datastructure/Element.java | 26 ++++++ .../datastructure/array/ArrayUtils.java | 7 +- .../binarytree/BinaryTreeNode.java | 24 ++++++ .../datastructure/linkedlist/LinkedList.java | 81 +++++++++++++++++++ .../linkedlist/LinkedListNode.java | 45 +++++++++++ .../algorithms/datastructure/queue/Queue.java | 23 ++++++ .../algorithms/datastructure/set/Set.java | 24 ++++++ .../algorithms/datastructure/stack/Stack.java | 28 +++++++ .../datastructure/vector/Vector.java | 53 ++++++++++++ 9 files changed, 310 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/Element.java b/src/main/java/io/github/diegourban/algorithms/datastructure/Element.java index 64d14f5..0ecd9a6 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/Element.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/Element.java @@ -1,17 +1,38 @@ package io.github.diegourban.algorithms.datastructure; +/** + * A named value stored by the data structures in this package. Two elements are equal when their names are equal. + */ public class Element { private final String name; + /** + * Creates an element with the given name. + * + * @param name the element's name + */ public Element(final String name) { this.name = name; } + /** + * Returns the element's name. + * + * @return the name given at construction + */ public String getName() { return name; } + /** + * Compares this element with another by name. The argument is cast without a type check, so passing an object + * that is not an {@code Element} fails with a {@code ClassCastException}. {@code hashCode} is not overridden. + * + * @param obj the object to compare with; must be an {@code Element} or {@code null} + * @return {@code true} if {@code obj} is an element with an equal name, {@code false} if {@code obj} is + * {@code null} + */ @Override public boolean equals(final Object obj) { if (obj == null) { @@ -21,6 +42,11 @@ public boolean equals(final Object obj) { return other.getName().equals(this.getName()); } + /** + * Returns the element's name. + * + * @return the name, same as {@link #getName()} + */ @Override public String toString() { return this.getName(); diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/array/ArrayUtils.java b/src/main/java/io/github/diegourban/algorithms/datastructure/array/ArrayUtils.java index 3b69505..c3c2c83 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/array/ArrayUtils.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/array/ArrayUtils.java @@ -2,6 +2,9 @@ import java.util.Random; +/** + * Static helper methods for arrays. + */ public final class ArrayUtils { private ArrayUtils() {} @@ -16,8 +19,10 @@ private ArrayUtils() {} * Crucially, once an item is placed at an index it can't be moved. So for the first index we choose from n items, for the second index we choose from n-1 items, etc *

* Complexity: O(1) space, and O(n) time. + *

+ * Arrays with zero or one element are left unchanged. * - * @param theArray the array to shuffle + * @param theArray the array to shuffle; modified in place */ public static void shuffle(final int[] theArray) { // if it's 1 or 0 items, just return diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/binarytree/BinaryTreeNode.java b/src/main/java/io/github/diegourban/algorithms/datastructure/binarytree/BinaryTreeNode.java index cbda92c..6e3c70f 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/binarytree/BinaryTreeNode.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/binarytree/BinaryTreeNode.java @@ -1,20 +1,44 @@ package io.github.diegourban.algorithms.datastructure.binarytree; +/** + * A node of a binary tree holding an {@code int} value. The tree is built by linking nodes through the public + * {@link #left} and {@link #right} fields. + */ public class BinaryTreeNode { + /** The value stored in this node. */ public int value; + /** The left child, or {@code null} if there is none. */ public BinaryTreeNode left; + /** The right child, or {@code null} if there is none. */ public BinaryTreeNode right; + /** + * Creates a leaf node with the given value. + * + * @param value the value to store + */ public BinaryTreeNode(final int value) { this.value = value; } + /** + * Sets a new leaf node as the left child, replacing any existing left subtree. + * + * @param leftValue the value of the new left child + * @return the new left child + */ public BinaryTreeNode insertLeft(final int leftValue) { this.left = new BinaryTreeNode(leftValue); return this.left; } + /** + * Sets a new leaf node as the right child, replacing any existing right subtree. + * + * @param rightValue the value of the new right child + * @return the new right child + */ public BinaryTreeNode insertRight(final int rightValue) { this.right = new BinaryTreeNode(rightValue); return this.right; diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java index 3e62bb9..9600a71 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedList.java @@ -2,12 +2,24 @@ import io.github.diegourban.algorithms.datastructure.Element; +/** + * A list of {@link Element}s implemented as a doubly linked chain of {@link LinkedListNode}s, keeping references to + * the first and last nodes and a running size. Positions are zero-based. + */ public class LinkedList { private LinkedListNode first = null; private LinkedListNode last = null; private int totalElements = 0; + /** Creates an empty list. */ + public LinkedList() {} + + /** + * Inserts an element at the start of the list. + * + * @param element the element to insert + */ public void addAtStart(final Element element) { if (this.totalElements == 0) { final LinkedListNode newNode = new LinkedListNode(element); @@ -22,6 +34,11 @@ public void addAtStart(final Element element) { this.totalElements++; } + /** + * Appends an element at the end of the list. + * + * @param element the element to append + */ public void addAtEnd(final Element element) { if (this.totalElements == 0) { addAtStart(element); @@ -35,6 +52,18 @@ public void addAtEnd(final Element element) { } } + /** + * Inserts an element at the given position, shifting later elements one position back. + *

+ * If the list is empty the element is added regardless of {@code position}. If {@code position} equals + * {@link #size()} the element is appended. Otherwise the element is linked after the node at + * {@code position - 1}, so inserting at position {@code 0} of a non-empty list is not supported. + * + * @param position the position for the new element, from {@code 1} to {@link #size()} on a non-empty list + * @param element the element to insert + * @throws IllegalArgumentException if the list is not empty and {@code position - 1} is not an occupied position + * (including {@code position == 0}) + */ public void add(final int position, final Element element) { if (this.totalElements == 0) { addAtStart(element); @@ -68,14 +97,31 @@ private LinkedListNode getNode(final int position) { return current; } + /** + * Returns the first node, giving direct access to the chain. + * + * @return the first node, or {@code null} if the list is empty + */ public LinkedListNode getFirst() { return this.first; } + /** + * Returns the element at the given position by walking from the first node. + * + * @param position the zero-based position + * @return the element at {@code position} + * @throws IllegalArgumentException if {@code position} is negative or not less than {@link #size()} + */ public Element get(final int position) { return this.getNode(position).getElement(); } + /** + * Removes the first element. + * + * @throws IllegalStateException if the list is empty + */ public void removeFromStart() { if (this.totalElements == 0) { throw new IllegalStateException("Lista vazia"); @@ -89,6 +135,10 @@ public void removeFromStart() { } } + /** + * Removes the last element. Unlike {@link #removeFromStart()}, calling this on an empty list fails with a + * {@code NullPointerException} rather than an {@code IllegalStateException}. + */ public void removeFromEnd() { if (this.totalElements == 1) { this.removeFromStart(); @@ -100,6 +150,20 @@ public void removeFromEnd() { } } + /** + * Removes the element at the given position. + *

+ * Position {@code 0} delegates to {@link #removeFromStart()} and position {@code size() - 1} to + * {@link #removeFromEnd()}; any other position unlinks the node after {@code position - 1}. + *

+ * Positions are not fully validated: on a non-empty list, {@code position == size()} fails with a + * {@code NullPointerException}, as does {@code -1} on an empty list. + * + * @param position the zero-based position, from {@code 0} to {@code size() - 1} + * @throws IllegalStateException if {@code position} is {@code 0} and the list is empty + * @throws IllegalArgumentException if {@code position} is negative or greater than {@link #size()}, except + * {@code -1} on an empty list + */ public void remove(final int position) { if (position == 0) { this.removeFromStart(); @@ -116,10 +180,21 @@ public void remove(final int position) { } } + /** + * Returns the number of elements. + * + * @return the number of elements in the list + */ public int size() { return this.totalElements; } + /** + * Tells whether the list holds an element equal to the given one, comparing with {@link Element#equals(Object)}. + * + * @param element the element to look for + * @return {@code true} if an equal element is found + */ public boolean contains(final Element element) { LinkedListNode current = this.first; while (current != null) { @@ -131,6 +206,12 @@ public boolean contains(final Element element) { return false; } + /** + * Returns the element names in order, each followed by a comma, inside brackets, for example {@code "[a,b,]"}; + * an empty list gives {@code "[]"}. + * + * @return the string form of the list + */ @Override public String toString() { if (this.totalElements == 0) { diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListNode.java b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListNode.java index 32f9f0e..11eef7f 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListNode.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/linkedlist/LinkedListNode.java @@ -2,6 +2,9 @@ import io.github.diegourban.algorithms.datastructure.Element; +/** + * A node of a doubly linked {@link LinkedList}, holding an {@link Element} and links to the previous and next nodes. + */ public class LinkedListNode { private Element element; @@ -9,35 +12,77 @@ public class LinkedListNode { private LinkedListNode previous; private LinkedListNode next; + /** + * Creates a node with no previous or next node. + * + * @param element the element to hold + */ public LinkedListNode(final Element element) { this(element, null); } + /** + * Creates a node linked forward to {@code next}. The previous link is left {@code null}, and {@code next} is not + * updated to point back. + * + * @param element the element to hold + * @param next the next node, or {@code null} + */ public LinkedListNode(final Element element, final LinkedListNode next) { this.element = element; this.next = next; } + /** + * Returns the element held by this node. + * + * @return the element + */ public Element getElement() { return element; } + /** + * Replaces the element held by this node. + * + * @param element the new element + */ public void setElement(final Element element) { this.element = element; } + /** + * Returns the next node. + * + * @return the next node, or {@code null} if this is the last node + */ public LinkedListNode getNext() { return next; } + /** + * Sets the next node. + * + * @param next the next node, or {@code null} + */ public void setNext(final LinkedListNode next) { this.next = next; } + /** + * Returns the previous node. + * + * @return the previous node, or {@code null} if none is linked + */ public LinkedListNode getPrevious() { return previous; } + /** + * Sets the previous node. + * + * @param previous the previous node, or {@code null} + */ public void setPrevious(final LinkedListNode previous) { this.previous = previous; } diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/queue/Queue.java b/src/main/java/io/github/diegourban/algorithms/datastructure/queue/Queue.java index dba0c9b..329323f 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/queue/Queue.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/queue/Queue.java @@ -3,18 +3,41 @@ import io.github.diegourban.algorithms.datastructure.Element; import java.util.LinkedList; +/** + * A first-in, first-out queue of {@link Element}s backed by a {@link java.util.LinkedList}. + */ public class Queue { private final LinkedList elements = new LinkedList<>(); + /** Creates an empty queue. */ + public Queue() {} + + /** + * Adds an element to the back of the queue. + * + * @param element the element to add + */ public void add(final Element element) { this.elements.add(element); } + /** + * Removes and returns the element at the front of the queue. On an empty queue this fails with the + * {@code IndexOutOfBoundsException} thrown by the backing list, instead of returning {@code null}. + * + * @return the oldest element in the queue + */ public Element poll() { return this.elements.remove(0); } + /** + * Returns the elements from front to back in {@link java.util.AbstractCollection#toString()} format, for example + * {@code "[a, b]"}. + * + * @return the string form of the queue + */ @Override public String toString() { return elements.toString(); diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/set/Set.java b/src/main/java/io/github/diegourban/algorithms/datastructure/set/Set.java index 1a8d3aa..1306ab4 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/set/Set.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/set/Set.java @@ -3,16 +3,28 @@ import java.util.LinkedList; import java.util.List; +/** + * A set of words implemented as a hash table of 26 buckets, each a {@link java.util.LinkedList}. A word's bucket is + * the character code of its lower-cased first character modulo 26, so buckets do not line up with alphabetical + * order ({@code 'a'} goes to bucket 19). + */ public class Set { private final List> table = new LinkedList>(); + /** Creates an empty set with 26 empty buckets. */ public Set() { for (int i = 0; i < 26; i++) { this.table.add(new LinkedList()); } } + /** + * Adds a word if it is not already present; duplicates are ignored. Comparison is case-sensitive. An empty + * string fails with a {@code StringIndexOutOfBoundsException}. + * + * @param word the word to add + */ public void add(final String word) { if (!contains(word)) { final int index = calculateTableIndex(word); @@ -21,6 +33,12 @@ public void add(final String word) { } } + /** + * Removes a word if present; otherwise does nothing. An empty string fails with a + * {@code StringIndexOutOfBoundsException}. + * + * @param word the word to remove + */ public void remove(final String word) { if (contains(word)) { final int index = calculateTableIndex(word); @@ -38,6 +56,12 @@ private int calculateTableIndex(final String word) { return word.toLowerCase().charAt(0) % 26; } + /** + * Returns all 26 buckets in index order, each in {@link java.util.AbstractCollection#toString()} format, for + * example {@code "[[], [], ..., [apple], ...]"}. + * + * @return the string form of the bucket table + */ @Override public String toString() { return this.table.toString(); diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/stack/Stack.java b/src/main/java/io/github/diegourban/algorithms/datastructure/stack/Stack.java index 33deeea..be0622f 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/stack/Stack.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/stack/Stack.java @@ -4,22 +4,50 @@ import java.util.LinkedList; import java.util.List; +/** + * A last-in, first-out stack of {@link Element}s backed by a {@link java.util.LinkedList}, whose end is the top. + */ public class Stack { private final List elements = new LinkedList<>(); + /** Creates an empty stack. */ + public Stack() {} + + /** + * Pushes an element onto the top of the stack. + * + * @param element the element to push + */ public void push(final Element element) { this.elements.add(element); } + /** + * Removes and returns the top element. On an empty stack this fails with the {@code IndexOutOfBoundsException} + * thrown by the backing list. + * + * @return the most recently pushed element + */ public Element pop() { return this.elements.remove(this.elements.size() - 1); } + /** + * Tells whether the stack is empty. + * + * @return {@code true} if the stack holds no elements + */ public boolean empty() { return this.elements.isEmpty(); } + /** + * Returns the elements from bottom to top in {@link java.util.AbstractCollection#toString()} format, for example + * {@code "[a, b]"}. + * + * @return the string form of the stack + */ @Override public String toString() { return this.elements.toString(); diff --git a/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java b/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java index e8fbb23..828aceb 100644 --- a/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java +++ b/src/main/java/io/github/diegourban/algorithms/datastructure/vector/Vector.java @@ -3,11 +3,23 @@ import io.github.diegourban.algorithms.datastructure.Element; import java.util.Arrays; +/** + * A growable list of {@link Element}s backed by an array that starts with capacity 100 and doubles when full. + * Positions are zero-based. + */ public class Vector { private Element[] elements = new Element[100]; private int totalElements = 0; + /** Creates an empty vector with capacity 100. */ + public Vector() {} + + /** + * Appends an element, growing the backing array if needed. + * + * @param element the element to append + */ public void add(final Element element) { this.guaranteesSpace(); @@ -15,6 +27,14 @@ public void add(final Element element) { this.totalElements++; } + /** + * Inserts an element at an occupied position, shifting it and later elements one position back. Only occupied + * positions are accepted, so this cannot append (use {@link #add(Element)}) or insert into an empty vector. + * + * @param position the zero-based position, from {@code 0} to {@code size() - 1} + * @param element the element to insert + * @throws IllegalArgumentException if {@code position} is negative or not less than {@link #size()} + */ public void add(final int position, final Element element) { if (!isPositionValid(position)) { throw new IllegalArgumentException("Invalid position"); @@ -32,6 +52,13 @@ private boolean isPositionValid(final int position) { return position >= 0 && position < totalElements; } + /** + * Returns the element at the given position. + * + * @param position the zero-based position + * @return the element at {@code position} + * @throws IllegalArgumentException if {@code position} is negative or not less than {@link #size()} + */ public Element get(final int position) { if (!positionOccupied(position)) { throw new IllegalArgumentException("Invalid position"); @@ -43,6 +70,14 @@ private boolean positionOccupied(final int position) { return position >= 0 && position < this.totalElements; } + /** + * Removes the element at the given position, shifting later elements one position forward. + *

+ * The position is not validated: a position not less than {@link #size()} removes the last element instead, and + * a negative position, or any call on an empty vector, fails with an {@code ArrayIndexOutOfBoundsException}. + * + * @param position the zero-based position, from {@code 0} to {@code size() - 1} + */ public void remove(final int position) { for (int i = position; i < this.totalElements - 1; i++) { this.elements[i] = this.elements[i + 1]; @@ -51,6 +86,13 @@ public void remove(final int position) { this.elements[this.totalElements] = null; } + /** + * Tells whether the vector holds an element equal to the given one, calling {@code element.equals} on each stored + * element. + * + * @param element the element to look for; must not be {@code null} + * @return {@code true} if an equal element is found + */ public boolean contains(final Element element) { for (int i = 0; i < this.totalElements; i++) { if (element.equals(this.elements[i])) { @@ -61,6 +103,11 @@ public boolean contains(final Element element) { return false; } + /** + * Returns the number of elements. + * + * @return the number of elements in the vector + */ public int size() { return this.totalElements; } @@ -75,6 +122,12 @@ private void guaranteesSpace() { } } + /** + * Returns the whole backing array, including the unused {@code null} slots, in the form + * {@code "Vector{elements=[a, b, null, ...]}"}. + * + * @return the string form of the vector + */ @Override public String toString() { return "Vector{" + "elements=" + Arrays.toString(elements) + '}'; From 68387b51f9b2971e056056bfe26f602b3ce9fec6 Mon Sep 17 00:00:00 2001 From: Diego Leonardo Urban Date: Fri, 6 Nov 2026 17:02:32 +0100 Subject: [PATCH 2/3] Document the math, io, string and sorting API with complete Javadoc Co-Authored-By: Claude Opus 5.5 --- .../diegourban/algorithms/io/Reader.java | 79 +++++++++++++++++++ .../algorithms/math/Combinatorics.java | 13 ++- .../diegourban/algorithms/math/Geometry.java | 44 +++++++++-- .../algorithms/math/Measurement.java | 9 ++- .../algorithms/math/NumberTheory.java | 49 ++++++++---- .../diegourban/algorithms/math/Numbers.java | 27 +++++-- .../diegourban/algorithms/math/Sequences.java | 21 +++-- .../algorithms/math/Statistics.java | 31 +++++--- .../algorithms/math/TriangleType.java | 12 +++ .../algorithms/sorting/InsertionSort.java | 6 +- .../algorithms/sorting/MergeSort.java | 5 +- .../algorithms/sorting/QuickSort.java | 7 +- .../algorithms/sorting/SelectionSort.java | 6 +- .../algorithms/string/StringUtils.java | 24 ++++++ 14 files changed, 281 insertions(+), 52 deletions(-) diff --git a/src/main/java/io/github/diegourban/algorithms/io/Reader.java b/src/main/java/io/github/diegourban/algorithms/io/Reader.java index c806c7d..a78e850 100644 --- a/src/main/java/io/github/diegourban/algorithms/io/Reader.java +++ b/src/main/java/io/github/diegourban/algorithms/io/Reader.java @@ -6,6 +6,15 @@ import java.io.InputStream; /** + * Fast, buffered reader of ASCII tokens and lines from an {@link InputStream}, for competitive programming. + *

+ * Input is read in 64 KiB chunks and decoded byte by byte, so only single-byte (ASCII) input is handled correctly. + * The token methods do no validation: any non-digit byte ends a number, and nothing checks for overflow. + *

+ * End of input: the first read past the end yields an end marker; any read after that throws {@link EOFException}. + * In practice the token methods throw {@code EOFException} when no further token remains, while {@link #readLine()} + * first returns whatever is left (possibly an empty string) and only throws on the following call. + *

* Solution extracted from * http://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/ */ @@ -16,12 +25,29 @@ public class Reader { private final byte[] buffer; private int bufferPointer, bytesRead; + /** + * Creates a reader over the given stream. Nothing is read until the first read method is called. + * + * @param input the stream to read from; it is closed by {@link #close()} + */ public Reader(final InputStream input) { din = new DataInputStream(input); buffer = new byte[BUFFER_SIZE]; bufferPointer = bytesRead = 0; } + /** + * Reads the next non-empty line. + *

+ * Leading {@code '\n'} and {@code '\r'} bytes are skipped, so blank lines are never returned; the line ends at + * the next {@code '\n'} or {@code '\r'}, which is consumed but not included. Lines longer than 10,000 bytes are + * not supported. + * + * @return the line without its terminator; the remaining text, or an empty string, if the input ends first + * @throws EOFException if a previous read already reached the end of the input + * @throws ArrayIndexOutOfBoundsException if the line is longer than 10,000 bytes + * @throws IOException if the underlying stream fails + */ public String readLine() throws IOException { final byte[] buf = new byte[10000]; // line length int cnt = 0; @@ -39,6 +65,16 @@ public String readLine() throws IOException { return new String(buf, 0, cnt); } + /** + * Reads the next whitespace-separated integer, with an optional leading {@code '-'}. + *

+ * Bytes up to and including {@code ' '} are skipped first. Digits are read until the first non-digit byte, + * which is consumed. Values outside the {@code int} range overflow silently. + * + * @return the integer read + * @throws EOFException if the input ends before a token is found + * @throws IOException if the underlying stream fails + */ public int nextInt() throws IOException { int ret = 0; byte c = read(); @@ -63,6 +99,13 @@ public int nextInt() throws IOException { return ret; } + /** + * Reads the next character that is not whitespace (any byte above {@code ' '}). + * + * @return the character read + * @throws EOFException if the input ends before such a character is found + * @throws IOException if the underlying stream fails + */ public char nextChar() throws IOException { byte c = read(); @@ -73,6 +116,15 @@ public char nextChar() throws IOException { return (char) c; } + /** + * Reads the next whitespace-separated long, with an optional leading {@code '-'}. + *

+ * Parses like {@link #nextInt()}; values outside the {@code long} range overflow silently. + * + * @return the long read + * @throws EOFException if the input ends before a token is found + * @throws IOException if the underlying stream fails + */ public long nextLong() throws IOException { long ret = 0; byte c = read(); @@ -97,6 +149,16 @@ public long nextLong() throws IOException { return ret; } + /** + * Reads the next whitespace-separated decimal number, such as {@code -12.5}. + *

+ * Accepts an optional leading {@code '-'}, digits and an optional {@code '.'} followed by digits. Exponent + * notation is not supported. The byte that ends the number is consumed. + * + * @return the number read + * @throws EOFException if the input ends before a token is found + * @throws IOException if the underlying stream fails + */ public double nextDouble() throws IOException { double ret = 0; double div = 1; @@ -128,6 +190,13 @@ public double nextDouble() throws IOException { return ret; } + /** + * Discards the next {@code n} bytes. + * + * @param n the number of bytes to discard; nothing happens if it is zero or negative + * @throws EOFException if a read is attempted after the end of the input was already reached + * @throws IOException if the underlying stream fails + */ public void skip(final int n) throws IOException { for (int i = 0; i < n; i++) { read(); @@ -156,6 +225,11 @@ private boolean isEOF() { return bytesRead == -1; } + /** + * Closes the underlying stream. Calling it again has no effect. + * + * @throws IOException if closing the underlying stream fails + */ public void close() throws IOException { if (din != null) { din.close(); @@ -163,6 +237,11 @@ public void close() throws IOException { } } + /** + * Tells whether {@link #close()} has been called. + * + * @return {@code true} if this reader is closed, {@code false} otherwise + */ public boolean isClosed() { return din == null; } diff --git a/src/main/java/io/github/diegourban/algorithms/math/Combinatorics.java b/src/main/java/io/github/diegourban/algorithms/math/Combinatorics.java index 19abf97..77efc07 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Combinatorics.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Combinatorics.java @@ -2,25 +2,32 @@ import java.math.BigInteger; +/** + * Combinatorics: binomial coefficients. + */ public final class Combinatorics { private Combinatorics() {} /** - * Pascal's Triangle - *

+ * Binomial coefficient "n choose m", read from Pascal's Triangle + *

      * 1
      * 1 1
      * 1 2 1
      * 1 3 3 1
      * 1 4 6 4 1
+     * 
+ *

+ * Builds row {@code n} of the triangle with exact {@link BigInteger} arithmetic: O(n²) time and O(n) space. *

* Solution extracted and adapted from * http://www.brpreiss.com/books/opus5/html/page460.html. * * @param n the row number (0-indexed) * @param m the column number (0-indexed) - * @return + * @return the number of ways to choose {@code m} items out of {@code n}; zero if {@code m} is negative or greater + * than {@code n} */ public static BigInteger binomialCoefficient(final int n, final int m) { if (m < 0 || m > n) { diff --git a/src/main/java/io/github/diegourban/algorithms/math/Geometry.java b/src/main/java/io/github/diegourban/algorithms/math/Geometry.java index 7d6ac5d..fd18210 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Geometry.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Geometry.java @@ -2,6 +2,11 @@ import java.util.Arrays; +/** + * Plane and solid geometry: distances, circles, polygons, cylinders and triangles. + *

+ * The circle and cylinder methods approximate pi as {@code 3.14}, not {@link Math#PI}. + */ public final class Geometry { private Geometry() {} @@ -23,7 +28,7 @@ public static double distance(final int x1, final int y1, final int x2, final in } /** - * Calculates the area of a circle from its radius + * Calculates the area of a circle from its radius, using pi = 3.14 * * @param radius the radius of the circle * @return the area of the circle @@ -33,7 +38,7 @@ public static double areaOfCircleFromRadius(final double radius) { } /** - * Calculates the area of a circle from its diameter + * Calculates the area of a circle from its diameter, using pi = 3.14 * * @param diameter the diameter of the circle * @return the area of the circle @@ -54,7 +59,7 @@ public static double radiusOfCircleFromDiameter(final double diameter) { } /** - * Calculates the radius of a circle from its area + * Calculates the radius of a circle from its area, using pi = 3.14 * * @param area the area of the circle * @return the radius of the circle @@ -64,7 +69,7 @@ public static double radiusOfCircleFromArea(final double area) { } /** - * Calculates the number of diagonals of an n-sided polygon + * Calculates the number of diagonals of an n-sided polygon, {@code sides * (sides - 3) / 2} * * @param sides the number of sides of the polygon * @return the amount of diagonals @@ -74,7 +79,7 @@ public static long diagonalsOfPolygonWithSides(final long sides) { } /** - * Calculates the height of a cylinder based on its volume and base radius + * Calculates the height of a cylinder based on its volume and base radius, using pi = 3.14 * * @param volume the cylinder volume * @param baseRadius the cylinder base radius @@ -85,17 +90,30 @@ public static double heightOfCylinder(final double volume, final double baseRadi } /** - * Checks if the sides a, b and c can form a valid triangle + * Checks if the sides a, b and c can form a valid triangle: each side must be shorter than the sum of the + * other two (strict triangle inequality, so degenerate triangles are rejected) * * @param a side a * @param b side b * @param c side c - * @return true if the sides form a valid triangle, false otherwise + * @return {@code true} if the sides form a valid triangle, {@code false} otherwise */ public static boolean isValidTriangle(final double a, final double b, final double c) { return (a + b > c) && (b + c > a) && (a + c > b); } + /** + * Classifies a triangle by how many of its sides are equal. + *

+ * The sides are compared exactly ({@code ==}) and are not checked to form a valid triangle; use + * {@link #isValidTriangle(double, double, double)} first. + * + * @param a side a + * @param b side b + * @param c side c + * @return {@link TriangleType#EQUILATERAL} if all three sides are equal, {@link TriangleType#ISOSCELES} if exactly + * two are, {@link TriangleType#ESCALENE} otherwise + */ public static TriangleType checkTriangleType(final double a, final double b, final double c) { final double[] array = new double[3]; array[0] = a; @@ -118,6 +136,18 @@ public static TriangleType checkTriangleType(final double a, final double b, fin return TriangleType.ESCALENE; } + /** + * Checks if the sides form a right ("rectangle") triangle, that is if the square of the longest side equals the + * sum of the squares of the other two (Pythagorean theorem). + *

+ * The comparison is exact ({@code ==}), so sides whose squares are not exactly representable as {@code double}, + * such as {@code 1, 1, Math.sqrt(2)}, may be rejected. The sides are not checked to form a valid triangle. + * + * @param a side a + * @param b side b + * @param c side c + * @return {@code true} if the sides satisfy the Pythagorean theorem, {@code false} otherwise + */ public static boolean isRectangleTriangle(final double a, final double b, final double c) { final double[] array = new double[3]; array[0] = a; diff --git a/src/main/java/io/github/diegourban/algorithms/math/Measurement.java b/src/main/java/io/github/diegourban/algorithms/math/Measurement.java index 5a7be66..37f9f2a 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Measurement.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Measurement.java @@ -1,11 +1,16 @@ package io.github.diegourban.algorithms.math; +/** + * Unit conversions between miles and kilometers. + *

+ * The two factors are not exact inverses of each other, so a round trip does not return exactly the original value. + */ public final class Measurement { private Measurement() {} /** - * Converts miles to kilometers + * Converts miles to kilometers, using 1 mile = 1.609344 km * * @param miles the amount of miles to convert * @return the amount of miles converted to kilometers @@ -15,7 +20,7 @@ public static double milesToKilometers(final double miles) { } /** - * Converts kilometers to miles + * Converts kilometers to miles, using 1 km = 0.621371 miles * * @param kilometers the amount of kilometers to convert * @return the amount of kilometers converted to miles diff --git a/src/main/java/io/github/diegourban/algorithms/math/NumberTheory.java b/src/main/java/io/github/diegourban/algorithms/math/NumberTheory.java index fd1a5c1..8297bf7 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/NumberTheory.java +++ b/src/main/java/io/github/diegourban/algorithms/math/NumberTheory.java @@ -11,10 +11,14 @@ private NumberTheory() {} /** * Least common multiple (lcm) of two numbers. + *

+ * Computed as {@code a * (b / gcdLoop(a, b))}; intended for positive numbers. The result overflows silently if it + * does not fit in a {@code long}. * - * @param a - * @param b + * @param a the first number + * @param b the second number * @return The least common multiple of two numbers. + * @throws ArithmeticException if both {@code a} and {@code b} are zero */ public static long lcm(final long a, final long b) { return a * (b / gcdLoop(a, b)); @@ -23,8 +27,10 @@ public static long lcm(final long a, final long b) { /** * Least common multiple (lcm) of an array of numbers. * - * @param input array of numbers - * @return The least common multiple of an array of numbers. + * @param input array of numbers; must not be empty + * @return The least common multiple of an array of numbers; the element itself for a one-element array. + * @throws ArrayIndexOutOfBoundsException if {@code input} is empty + * @see #lcm(long, long) */ public static long lcm(final long[] input) { long result = input[0]; @@ -37,9 +43,12 @@ public static long lcm(final long[] input) { *

* Also known as greatest common factor (gcf), highest common factor (hcf), * greatest common measure (gcm) or highest common divisor + *

+ * Correct for non-negative input. The loop only runs while {@code b} is positive, so a negative {@code b} + * returns {@code a} unchanged; {@code gcdLoop(a, 0)} returns {@code a}. * - * @param a - * @param b + * @param a the first number + * @param b the second number * @return The greatest common divisor of two numbers. */ public static long gcdLoop(final long a, final long b) { @@ -58,10 +67,13 @@ public static long gcdLoop(final long a, final long b) { *

* Also known as greatest common factor (gcf), highest common factor (hcf), * greatest common measure (gcm) or highest common divisor + *

+ * Correct for non-negative input. Negative input is accepted, but the result may be negative (Java's {@code %} + * keeps the sign of the dividend), so it can differ in sign from {@link #gcdLoop(long, long)}. * - * @param a - * @param b - * @return The greatest common divisor of two numbers. + * @param a the first number + * @param b the second number + * @return The greatest common divisor of two numbers; {@code a} if {@code b} is zero. */ public static long gcdRecursive(final long a, final long b) { return b == 0 ? a : gcdRecursive(b, a % b); @@ -71,9 +83,11 @@ public static long gcdRecursive(final long a, final long b) { * Checks if a number is prime. *

* Based on https://en.wikipedia.org/wiki/Primality_test + *

+ * Trial division by 2, 3 and numbers of the form 6k ± 1 up to the square root of {@code n}: O(√n) time. * - * @param n - * @return true if the number n is prime, false otherwise + * @param n the number to test + * @return {@code true} if the number n is prime, {@code false} otherwise (including for {@code n <= 1}) */ public static boolean isPrime(final int n) { if (n <= 1) { @@ -97,9 +111,12 @@ public static boolean isPrime(final int n) { /** * Lists the prime factors of a number. + *

+ * Uses trial division up to the square root of {@code number}: O(√n) time. * - * @param number - * @return The list of prime factors of a number. + * @param number the number to factorise + * @return The list of prime factors of a number, in ascending order and repeated by multiplicity (12 gives + * {@code [2, 2, 3]}); empty for numbers below 2. */ public static List primeFactorsList(final int number) { final List factors = new ArrayList<>(); @@ -110,8 +127,10 @@ public static List primeFactorsList(final int number) { /** * Build the set of prime factors of a number. * - * @param number - * @return The set of prime factors of a number. + * @param number the number to factorise + * @return The set of distinct prime factors of a number (12 gives {@code {2, 3}}), in no particular order; + * empty for numbers below 2. + * @see #primeFactorsList(int) */ public static Set primeFactorsSet(final int number) { final Set factors = new HashSet<>(); diff --git a/src/main/java/io/github/diegourban/algorithms/math/Numbers.java b/src/main/java/io/github/diegourban/algorithms/math/Numbers.java index 08323d5..50f5268 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Numbers.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Numbers.java @@ -1,15 +1,21 @@ package io.github.diegourban.algorithms.math; +/** + * Digit-level operations on integers. + */ public final class Numbers { private Numbers() {} /** * Checks if a number contains a digit + *

+ * The sign of {@code number} is ignored. The number {@code 0} is treated as having no digits, so + * {@code containsDigit(0, 0)} returns {@code false}. * * @param number the number to check * @param digit the digit expected to find in the number - * @return true if the number contains the digit, false otherwise + * @return {@code true} if the number contains the digit, {@code false} otherwise */ public static boolean containsDigit(final long number, final long digit) { long thisNumber = number >= 0 ? number : -number; @@ -30,10 +36,14 @@ public static boolean containsDigit(final long number, final long digit) { /** * Checks if a number contains repeating digits + *

+ * Only consecutive repetitions count: {@code 1221} repeats {@code 2} twice, {@code 1212} has no repetition. + * Zero and negative numbers always return {@code false}, as does a {@code times} below 2. * * @param number the number * @param times amount of times a digit must repeat - * @return true if the number contains a digit repeating at least the expected amount of times, false otherwise + * @return {@code true} if the number contains a digit repeating consecutively at least the expected amount of + * times, {@code false} otherwise */ public static boolean containsRepeatingDigits(final long number, final int times) { long theNumber = number; @@ -57,10 +67,15 @@ public static boolean containsRepeatingDigits(final long number, final int times } /** - * Converts a number to an array + * Converts a number to an array of its digits, least significant digit first: {@code 123} becomes + * {@code [3, 2, 1]}. + *

+ * Intended for non-negative numbers that fit in an {@code int}: each step truncates the number to {@code int} + * before taking the last digit, so larger values give wrong digits, and a negative number gives negative digits + * plus an extra trailing {@code 0} for the minus sign. * * @param number the number to convert - * @return an array with each digit of the number + * @return an array with each digit of the number, in reverse order */ public static int[] toArray(final long number) { long theNumber = number; @@ -78,9 +93,11 @@ public static int[] toArray(final long number) { /** * Find the length of the int using divide and conquer + *

+ * Intended for non-negative numbers: any negative number returns 1. * * @param number some number - * @return the length of the number + * @return the number of decimal digits of the number, from 1 to 10 */ public static int length(final int number) { if (number < 100000) { diff --git a/src/main/java/io/github/diegourban/algorithms/math/Sequences.java b/src/main/java/io/github/diegourban/algorithms/math/Sequences.java index 087dcf8..54f4064 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Sequences.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Sequences.java @@ -13,14 +13,15 @@ private Sequences() {} /** * Calculates the nth Fibonacci number. - * Works with n <= 46 + * Works with n <= 46; larger values overflow {@code int} silently and return a wrong result. *

* Solution: Using a bottom-up approach, starting with the 0th fibonacci number and iteratively computing subsequent numbers until we get to n. *

- * Complexity: N time and O(1) space. + * Complexity: O(n) time and O(1) space. * - * @param n the nth number in the Fibonacci sequence to calculate + * @param n the nth number in the Fibonacci sequence to calculate, with {@code fibonacci(0) == 0} * @return the nth Fibonacci number + * @throws IllegalArgumentException if {@code n} is negative */ public static int fibonacci(final int n) { // edge cases: @@ -52,10 +53,14 @@ public static int fibonacci(final int n) { /** * Calculates the nth Fibonacci number. - * Works with n <= 67 + * Works with n <= 67 + *

+ * Uses Binet's formula in {@code double} arithmetic, so the result is approximate (for example + * {@code 55.000000000000014} for n = 10). Rounded with {@link Math#round(double)}, it equals the exact value for + * 0 <= n <= 67. Negative {@code n} is not rejected and gives a meaningless result. * * @param n the nth number in the Fibonacci sequence to calculate - * @return the nth Fibonacci number + * @return an approximation of the nth Fibonacci number */ public static double fibonacciSimpleBinetFormula(final int n) { if (n == 0) { @@ -68,7 +73,11 @@ public static double fibonacciSimpleBinetFormula(final int n) { /** * Calculates the nth Fibonacci number. - * Works with n <= 71 + * Works with n <= 71 + *

+ * Uses Binet's formula, with the powers computed in {@code double} and the subtraction and division done in + * {@link BigDecimal}. The result is exact for 0 <= n <= 71 and drifts from the true value after that. + * Negative {@code n} is not rejected and gives a meaningless result. * * @param n the nth number in the Fibonacci sequence to calculate * @return the nth Fibonacci number diff --git a/src/main/java/io/github/diegourban/algorithms/math/Statistics.java b/src/main/java/io/github/diegourban/algorithms/math/Statistics.java index 5098b6c..d852c62 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/Statistics.java +++ b/src/main/java/io/github/diegourban/algorithms/math/Statistics.java @@ -2,6 +2,9 @@ import java.util.Arrays; +/** + * Descriptive statistics over arrays of {@code double}: mean, median, mode and mean absolute deviation. + */ public final class Statistics { private Statistics() {} @@ -10,8 +13,8 @@ private Statistics() {} * An average is the sum of a list of numbers divided by the number of * numbers in the list. * - * @param data - * @return + * @param data the values to average + * @return the arithmetic mean of {@code data}, or {@code 0.0} if it is empty */ public static double mean(final double[] data) { if (data.length == 0) { @@ -27,10 +30,14 @@ public static double mean(final double[] data) { } /** - * The median is the value separating the higher half of a data sample + * The median is the value separating the higher half of a data sample from the lower half. + *

+ * Note: {@code data} is sorted in place, so the caller's array is modified. Pass a copy to keep the original + * order. * - * @param data - * @return + * @param data the values; must not be empty, and is sorted ascending as a side effect + * @return the middle value for an odd number of values, or the mean of the two middle values for an even number + * @throws ArrayIndexOutOfBoundsException if {@code data} is empty */ public static double median(final double[] data) { Arrays.sort(data); @@ -46,9 +53,12 @@ public static double median(final double[] data) { /** * The mode is the value that appears most often in a set of data. + *

+ * Values are compared with {@code ==}. Runs in O(n²) time. * - * @param data - * @return + * @param data the values + * @return the most frequent value; on a tie, the one that appears first in {@code data}; {@code 0.0} if + * {@code data} is empty */ public static double mode(final double[] data) { double maxValue = 0; @@ -70,10 +80,11 @@ public static double mode(final double[] data) { /** * The average absolute deviation (or mean absolute deviation) of a data set - * is the average of the absolute deviations from a central point + * is the average of the absolute deviations from a central point; here the central point is the + * {@linkplain #mean(double[]) mean}. * - * @param data - * @return the Average Absolute Deviation from data + * @param data the values + * @return the Average Absolute Deviation from data; {@code NaN} if {@code data} is empty */ public static double meanAbsoluteDeviation(final double[] data) { final double mean = mean(data); diff --git a/src/main/java/io/github/diegourban/algorithms/math/TriangleType.java b/src/main/java/io/github/diegourban/algorithms/math/TriangleType.java index 41c7d91..e7df295 100644 --- a/src/main/java/io/github/diegourban/algorithms/math/TriangleType.java +++ b/src/main/java/io/github/diegourban/algorithms/math/TriangleType.java @@ -1,8 +1,15 @@ package io.github.diegourban.algorithms.math; +/** + * Classification of a triangle by how many of its sides are equal, as returned by + * {@link Geometry#checkTriangleType(double, double, double)}. + */ public enum TriangleType { + /** All three sides are equal. */ EQUILATERAL("Equilatero"), + /** No two sides are equal (scalene). */ ESCALENE("Escaleno"), + /** Exactly two sides are equal. */ ISOSCELES("Isoceles"); private final String name; @@ -11,6 +18,11 @@ private TriangleType(final String name) { this.name = name; } + /** + * Returns the display name of this type, in Portuguese. + * + * @return the display name, such as {@code "Equilatero"} + */ public String getName() { return name; } diff --git a/src/main/java/io/github/diegourban/algorithms/sorting/InsertionSort.java b/src/main/java/io/github/diegourban/algorithms/sorting/InsertionSort.java index 3fa938c..01ccbd6 100644 --- a/src/main/java/io/github/diegourban/algorithms/sorting/InsertionSort.java +++ b/src/main/java/io/github/diegourban/algorithms/sorting/InsertionSort.java @@ -1,10 +1,14 @@ package io.github.diegourban.algorithms.sorting; /** - * Insertion Sort Algorithm + * Insertion Sort Algorithm: moves each element left past larger ones until it is in place; + * O(n²) time (O(n) on already sorted input) and O(1) extra space. */ public class InsertionSort implements Sorter { + /** Creates an insertion sort. */ + public InsertionSort() {} + @Override public void sort(final int[] items) { sort(items, items.length); diff --git a/src/main/java/io/github/diegourban/algorithms/sorting/MergeSort.java b/src/main/java/io/github/diegourban/algorithms/sorting/MergeSort.java index 2a2779d..3ee1e38 100644 --- a/src/main/java/io/github/diegourban/algorithms/sorting/MergeSort.java +++ b/src/main/java/io/github/diegourban/algorithms/sorting/MergeSort.java @@ -1,10 +1,13 @@ package io.github.diegourban.algorithms.sorting; /** - * Merge sort algorithm + * Merge sort algorithm: recursively sorts each half and merges them; O(n log n) time and O(n) extra space. */ public class MergeSort implements Sorter { + /** Creates a merge sort. */ + public MergeSort() {} + @Override public void sort(final int[] items) { sort(items, 0, items.length); diff --git a/src/main/java/io/github/diegourban/algorithms/sorting/QuickSort.java b/src/main/java/io/github/diegourban/algorithms/sorting/QuickSort.java index b34a40a..9ebf87d 100644 --- a/src/main/java/io/github/diegourban/algorithms/sorting/QuickSort.java +++ b/src/main/java/io/github/diegourban/algorithms/sorting/QuickSort.java @@ -1,10 +1,15 @@ package io.github.diegourban.algorithms.sorting; /** - * Quick sort algorithm + * Quick sort algorithm: partitions around the last element (Lomuto scheme) and recurses on both sides; + * O(n log n) average and O(n²) worst-case time (for example on already sorted input), O(log n) average and O(n) + * worst-case stack space. */ public class QuickSort implements Sorter { + /** Creates a quick sort. */ + public QuickSort() {} + @Override public void sort(final int[] items) { sort(items, 0, items.length); diff --git a/src/main/java/io/github/diegourban/algorithms/sorting/SelectionSort.java b/src/main/java/io/github/diegourban/algorithms/sorting/SelectionSort.java index 2cdde3a..11f8ba8 100644 --- a/src/main/java/io/github/diegourban/algorithms/sorting/SelectionSort.java +++ b/src/main/java/io/github/diegourban/algorithms/sorting/SelectionSort.java @@ -1,10 +1,14 @@ package io.github.diegourban.algorithms.sorting; /** - * Selection Sort algorithm + * Selection Sort algorithm: repeatedly swaps the smallest remaining element into place; O(n²) time in + * every case and O(1) extra space. */ public class SelectionSort implements Sorter { + /** Creates a selection sort. */ + public SelectionSort() {} + @Override public void sort(final int[] items) { sort(items, items.length); diff --git a/src/main/java/io/github/diegourban/algorithms/string/StringUtils.java b/src/main/java/io/github/diegourban/algorithms/string/StringUtils.java index b7c92ea..8db1e12 100644 --- a/src/main/java/io/github/diegourban/algorithms/string/StringUtils.java +++ b/src/main/java/io/github/diegourban/algorithms/string/StringUtils.java @@ -2,10 +2,23 @@ import java.util.*; +/** + * String checks: palindromes and anagrams. + */ public final class StringUtils { private StringUtils() {} + /** + * Checks if a string reads the same forwards and backwards. + *

+ * The comparison is exact, character by character: case, spaces and punctuation all count, so {@code "Aba"} is + * not a palindrome. Runs in O(n) time. + * + * @param theString the string to check + * @return {@code true} if the string is a palindrome; {@code false} otherwise, including for {@code null} and the + * empty string + */ public static boolean isPalindrome(final String theString) { if (theString == null || theString.isEmpty()) { return false; @@ -25,6 +38,17 @@ public static boolean isPalindrome(final String theString) { return true; } + /** + * Checks if two strings are anagrams: the same characters, each the same number of times, in any order. + *

+ * The comparison ignores case (both strings are lower-cased first) but counts spaces and punctuation. Runs in + * O(n log n) time by sorting the characters of both strings. + * + * @param a the first string; must not be {@code null} + * @param b the second string; must not be {@code null} + * @return {@code true} if the strings are anagrams of each other, {@code false} otherwise + * @throws NullPointerException if {@code a} or {@code b} is {@code null} + */ public static boolean isAnagram(final String a, final String b) { if (a.length() != b.length()) { return false; From f9223dae21fdf40549d3156171f310a238bc8f98 Mon Sep 17 00:00:00 2001 From: Diego Leonardo Urban Date: Fri, 6 Nov 2026 17:02:49 +0100 Subject: [PATCH 3/3] Enforce complete Javadoc on the library with doclint default-compile now runs with -Xdoclint:all/protected -Werror, so any public or protected library member without complete Javadoc fails the build. Test and problem sources are not affected. Co-Authored-By: Claude Opus 5.5 --- pom.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pom.xml b/pom.xml index 88bbf7e..64f6933 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,21 @@ + + maven-compiler-plugin + + + + default-compile + + + -Xdoclint:all/protected + -Werror + + + + + maven-enforcer-plugin ${maven-enforcer-plugin.version}