Releases: vavr-io/vavr
Major Release 0.9
Changes to the Base Package io.vavr
We removed the interfaces Kind1
and Kind2
. They served as bridge for the removed module javaslang-pure
, which contained experimental algebraic extensions.
Values
- We removed
getOption()
in favor oftoOption()
(which has the same semantics) - We changed the functional interface argument of
getOrElseTry(CheckedFunction0)
(was:getOrElseTry(Try.CheckedSupplier)
) - We removed the conversion method
toStack()
- We replaced the conversion methods
toJavaList(Supplier)
bytoJavaList(Function)
toJavaSet(Supplier)
bytoJavaSet(Function)
- We added introspection methods
isAsync()
andisLazy()
that provide information about aValue
type at runtime - We added
getOrNull()
which returnsnull
if theValue
is empty - We added Java-like
collect()
methods - We added several conversion methods:
toCompletableFuture()
toEither(Supplier)
toEither(L)
toInvalid(Supplier)
toInvalid(T)
toJavaArray(Class)
toJavaCollection(Function)
toJavaCollection(Supplier)
toJavaList(Function)
- `toJavaMap(Supplier, Function, Function
toJavaParallelStream()
toJavaSet(Function)
toLinkedMap(Function)
toLinkedMap(Function, Function)
toLinkedSet()
toMap(Function, Function)
toPriorityQueue()
toPriorityQueue(Comparator)
toSortedMap(Comparator, Function)
toSortedMap(Comparator, Function, Function)
toSortedMap(Function)
toSortedMap(Function, Function)
toSortedSet()
toSortedSet(Comparator)
toValid(Supplier)
toValid(E)
toValidation(Supplier)
toValidation(L)
Functions
We removed the interface λ (the mother of all functions). It was neat but it had no practical purpose. The unicode character caused several problems with 3rd party tools, which did not handle unicode characters properly.
- We renamed the interface
io.vavr.λ
toio.vavr.Lambda
and removed it from the public API. - We removed the interface
λ.Memoized
from the public API.
We added PartialFunction
, which is an enabler for
- a more performant pattern matching implementation
Functional interfaces
With Vavr 0.9 we bundled our functions in io.vavr
.
- We moved the functional interfaces
Try.CheckedConsumer
,Try.CheckedPredicate
,Try.CheckedRunnable
toio.vavr
. - We replaced the functional interface
Try.CheckedSupplier
by the existingCheckedFunction0
.
Exception Handling
We added some methods to
- uncheck an existing throwing function, e.g.
CheckedFunction(x -> { throw new Error(); }).unchecked()
- lift checked functions to an
Option
return type, e.g.// = None
CheckedFunction1.lift(x -> { throw new Error(); }).apply(o);
- lift checked functions to a
Try
return type, e.g.// = Failure(Error)
CheckedFunction1.liftTry(x -> { throw new Error(); }).apply(o);
Other Factory Methods
- create constant functions, e.g.
Function2.constant(1).apply(what, ever); // = 1
- narrowing the generic types, e.g.
Function0<? extends CharSequence> f_ = () -> "hi";
Function0<CharSequence> f = Function0.narrow(f_);
Tuples
- We renamed
transform()
toapply()
, e.g.y = f(x1, x2, x3)
can be understood asy = Tuple(x1, x2, x3).apply(f)
.
Additions:
- Tuple fields can be updated using one of the
update*
methods, e.g.Tuple(1, 2, 3).update2(0)
. - A Tuple2 can be swapped, e.g.
Tuple(1, 2).swap()
. - Tuples can be created from
java.util.Map.Entry
instances, e.g.Tuple.fromEntry(entry) // = Tuple2
- Tuples can be sequenced, e.g.
Tuple.sequence1(Iterable<? extends Tuple1<? extends T1>>) // = Tuple1<Seq<T1>>
- Tuples can be narrowed, e.g.
Tuple.narrow(Tuple1<? extends T1>) // = Tuple1<T1>
The API Gateway
We added io.vavr.API
that gives direct access to most of the Vavr API without additional imports.
We are now able to start using Vavr by adding one gateway import. More imports can be added on demand by the IDE.
'Companion' Factory Methods
import static io.vavr.API.*;
The new static factory methods serve two things:
- They add syntactic sugar.
E.g. instead of Try.of(() -> new Error())
we now just write Try(() -> new Error())
.
- They reflect the expected return type.
Try<Integer> _try = Try(1);
Success<Integer> success = Success(1);
Failure<Integer> failure = Failure(new Error());
Option<Integer> option = Option(1);
Some<Integer> some = Some(1);
None<Integer> none = None();
Array<Integer> array = Array(1, 2, 3);
List<Integer> list = List(1, 2, 3);
Stream<Integer> stream = Stream(1, 2, 3);
Vector<Integer> vector = Vector(1, 2, 3);
Tuple1<T> tuple1 = Tuple(t);
Tuple3<T, U, V> tuple3 = Tuple(t, u, v);
E.g. Some(1)
is expected to be Option.Some
, not Option
. However, type narrowing is possible.
// types work as expected
Option<CharSeqeuence> option = Some("");
// `str` might be null
Option<CharSeqeuence> option = Option(str);
// also possible, it is a Some(null)!
Option<CharSeqeuence> option = Some(null);
Uncheck Functions
We are now able to uncheck checked functions:
Function1<String, User> getUserById = CheckedFunction1.of(id -> throw new IOException()).unchecked();
// = CheckedFunction1.of(User::getById).unchecked();
It is recommended to use the API.unchecked()
shortcut instead:
Function1<String, User> getUserById = unchecked(id -> throw new IOException());
// = unchecked(User::getById);
More Syntacic Sugar
We are now able to println
to console without having to type the System.out
boilerplate.
println("easy");
Rapid prototyping may require to defer implementations. We use TODO()
for that purpose:
void fancyNewAlgorithm(Arg arg) {
return TODO("some fancy stuff will appear soon");
}
fancyNewAlgorithm(TODO("need to construct the `arg`"));
The TODO()
calls will throw a NotImplementedError
at runtime.
Pattern Matching
Internally pattern matching now uses the new PartialFunction
interface, which gives a performance boost.
Pattern Names
We removed the possibility to create pattern matching cases outside of the pattern scope. Now we always use the existing $()
methods to lift objects and functions into a pattern context.
// before
Case(obj, ...) // e.g. Case(1, ...)
Case(predicate, ...) // e.g. Case(t -> true, ...)
// after
Case($(obj), ...) // e.g. Case($(1), ...)
Case($(predicate), ...) // e.g. Case($(t -> true), ...)
Our pattern generator vavr-match
follows the new naming scheme and adds a $
to all generated pattern names.
Please prefix all patterns with $
, e.g. $Some(...)
instead of Some(...)
.
import static io.vavr.API.*;
import static io.vavr.Patterns.*;
// same as `intOption.map(i -> i * 2).getOrElse(-1)`
String result = Match(intOption).of(
Case($Some($()), i -> i * 2),
Case($None(), -1)
);
More details here.
Pre-defined Patterns
Accordingly all pattern names in io.vavr.Patterns
are now prefixed with a $
, and
- we replaced the
List()
patterns by$Cons(...)
and$Nil()
. - we removed the
Stream()
patterns because we need to enhance our pattern generator to express inner patterns$Stream.Cons(...)
and$Stream.Empty()
(API not finished).
More details here.
Pre-defined Predicates
We added the predicates:
exists(Predicate)
forAll(Predicate)
instanceOf(Class)
isNotNull()
isNull()
More details here.
Changes to the Base Package io.vavr.control
Try keeps original Exception
- We removed
Try.FatalException
andTry.NonFatalException
- Instead we sneaky throw the original exception when calling
get()
(even if it is checked!)
For additions see the Try API.
Changes to the Collections io.vavr.collection
- We removed
AbstractIterator
from the public API - We changed the index type from
long
toint
. That strikes many methods, liketake(int)
,drop(int)
,zipWithIndex()
, ... - We removed the unsafe
Map.of(Object...)
factory methods which interpreted the given objects as pairs. - We added the safe
Map.of(K, V, ...)
factory methods (up to 10 key/value pairs).
Java Collection Views
Our sequential collections, i.e. all collections that implement Seq
, can be converted to a java.util collection view in O(1).
We provide conversion method for mutable and immutable collections. By default collections are immutable, like our persistent collections.
java.util.List<Integer> list = Vector(1, 2, 3).asJava();
More examples can be found here.
More Collections
We completely re-implemented Vector
.
We added more collections:
BitSet
PriorityQueue
Multimap
:HashMultimap
andLinkedHashMultimap
SortedMultimap
:TreeMultimap
The collections g...
Bugfix Release 2.0.6
Committers
Daniel Dietrich
Gregor Trefs
Jan Ferko
Pap Lőrinc
Przemek Wesołek
Ruslan Sennov
Changelog
Base
#1891 Changed generic bounds of Predicates allOf(), anyOf() and noneOf()
We needed to change the signatures because some Match expressions did not compile.
- public static <T> Predicate<T> allOf(Predicate<? super T>... predicates) { ... }
+ public static <T> Predicate<T> allOf(Predicate<T>... predicates) { ... }
Instead of
Match(value).of(
Case(instanceOf(Either.LeftProjection.class), false),
Case(instanceOf(Either.RightProjection.class), false),
Case(instanceOf(Future.class), false),
Case(instanceOf(Iterator.class), false),
Case(instanceOf(Validation.class), false),
Case(instanceOf(Either.class), true),
Case(instanceOf(Option.class), true),
Case(instanceOf(Try.class), true),
Case(instanceOf(Traversable.class), true)
);
we are now able to write
Match(value).of(
Case(anyOf(
instanceOf(Either.LeftProjection.class),
instanceOf(Either.RightProjection.class),
instanceOf(Future.class),
instanceOf(Iterator.class),
instanceOf(Validation.class)
), false),
Case(anyOf(
instanceOf(Either.class),
instanceOf(Option.class),
instanceOf(Try.class),
instanceOf(Traversable.class)
), true)
);
The second variant did not compile before.
#1892 Make interfaces Serializable
We (unintentionally) changed the interface serializability. E.g. Option wasn't serializable any more (but the classes Some and None are). This hindered us from adding fields of interface types (like Option) to serializable classes.
Now interfaces extend Serializable. We made an exception for stateful types like Future, Promise and Iterator. These interfaces still to not extend Serializable.
Collections
#1796 Fixed stackoverflow problem of List.hashCode().
The hashCode() calculation for big lists now works as expected.
List.range(0, 1_000_000)).hashCode();
Note: Additionally we changed the hashCode() of the empty HashArrayMappedTrie, which is the basis for HashMap and HashSet.
#1792 Fixes deadlock on concurrent class initialization
We could provoke a deadlock when concurrently using Iterators and the Iterator class wasn't yet initialized by the underlying ClassLoader:
import javaslang.collection.AbstractIterator;
import javaslang.collection.Iterator;
/**
* Created by aeremeev on 25.12.16.
*/
public class DeadlockTest {
public static void main(String[] args) {
new Thread(Iterator::empty).start();
new A();
System.out.println("Success");
}
private static class A extends AbstractIterator<Void> {
@Override
protected Void getNext() {
return null;
}
@Override
public boolean hasNext() {
return false;
}
}
}
#1816, #1823 HashArrayMappedTrie.equals() and LeafList.hashCode() fixed
The following maps should be equal because there is no underlying order.
final Map<String, Integer> map1 = HashMap.of("Aa", 1, "BB", 2);
final Map<String, Integer> map2 = HashMap.of("BB", 2, "Aa", 1);
assertThat(map1).isEqualTo(map2);
Please note that we provoked a hash collision in the example above:
jshell> "Aa".hashCode()
$1 ==> 2112
jshell> "BB".hashCode()
$2 ==> 2112
#1854 LinkedHashMap.keySet() order
The key set of a LinkedHashMap needs to be a linked set.
final Set<Integer> keySet = LinkedHashMap.of(4, "d", 1, "a", 2, "b").keySet();
assertThat(keySet.mkString()).isEqualTo("412");
#1858 Set.add(existing) does nothing, Map.put(existing, any) overwrites
The Javaslang implementation now acts like this:
Set | ovewrites equal elements |
---|---|
BitSet | no |
HashSet | no |
LinkedHashSet | no |
TreeSet | no |
Map | ovewrites (k,v) when key equal, value unequal |
ovewrites (k,v) when key equal, value equal |
overwrites old key with new key |
---|---|---|---|
HashMap | yes | yes | yes |
LinkedHashMap | yes (appends) | yes (appends) | yes |
TreeMap | yes | yes | yes |
There is one anomaly in Scala: Despite all other Map implementations, HashMap does not update (key, value) when putting a (key, value) that is already present.
Especially this may bite the user when working with the Map interface and it is not clear which implementations is currently used (see Liskov Substitution Principle).
In Javaslang, we do consistent updates along all Map implementations.
#1878 Fixes Traversable.containsAll(Iterable)
I can't think what came over me.
default boolean containsAll(Iterable<? extends T> elements) {
- final HashSet<T> uniqueElements = HashSet.ofAll(elements);
- return toSet().intersect(uniqueElements).size() == uniqueElements.size();
+ for (T element : elements) {
+ if (!contains(element)) {
+ return false;
+ }
+ }
+ return true;
}
#1907 Fixes memory leak of grouped iterator
Infinite iterators can be grouped now in constant memory:
Iterator.continually(1)
.grouped(100)
.zipWithIndex()
.forEach(t -> System.out.println("Group " + t._2));
Functions
#1837 Changed memoization's computeIfAbsent to synchronized get and put
We now support function value memoization in recursive calls:
private static final Function2<Integer, Integer, Integer> recurrent1 = (i1, i2) -> i1 <= 0 ? i1 : Function2Test.recurrent2.apply(i1 - 1, i2) + 1;
private static final Function2<Integer, Integer, Integer> recurrent2 = Function2Test.recurrent1.memoized();
@Test
public void shouldCalculatedRecursively() {
assertThat(recurrent1.apply(11, 11)).isEqualTo(11);
assertThat(recurrent1.apply(22, 22)).isEqualTo(22);
}
Property Testing
#1700 Optimized random value generators
We now internally use Iterator instead of Stream:
static <T> Gen<T> of(T seed, Function<? super T, ? extends T> next) {
Objects.requireNonNull(next, "next is null");
- final Iterator<T> iterator = Stream.iterate(seed, next).iterator();
+ final Iterator<T> iterator = Iterator.iterate(seed, next);
return ignored -> iterator.next();
}
Additionally we rewrote
frequency(Iterable<Tuple2<Integer, Gen<T>>> generators)
intersperse(Gen<T> other)
Info: This change contains a backward compatible API change:
interface Gen<T> {
- static Gen<Character> choose(char[] characters) {
+ static Gen<Character> choose(char... characters) {
}
#1702 ArrayStoreException in Gen.choose(Iterable)
For instances of generic interfaces, choose was throwing an ArrayStoreException because of different runtime types of the elements within the iterable.
static <T> Gen<T> choose(Iterable<T> values) {
...
- final T[] array = stream.toJavaArray((Class<T>) stream.head().getClass());
+ final T[] array = (T[]) iterator.toJavaArray();
...
}
#1759 Gen.frequency filters non-positive frequencies
Now Gen.frequency(Iterable)
throws an IllegalArgumentException if there are non-positive frequencies (including zero).
Javadoc
#1735 Correct prefix-delimiter-suffix in mkString() javadoc
/**
...
- * This has the same effect as calling {@code mkString(delimiter, "", "")}.
+ * This has the same effect as calling {@code mkString("", delimiter, "")}.
...
*/
Bugfix Release 2.0.5
Committers
@ashrko619
@danieldietrich
@mduesterhoeft
@paplorinc
@ruslansennov
New and Noteworthy
API Additions
Javaslang follows the semantic versioning scheme. In the strict sense API additions require a minor version update. However, the additions that are contained in this bugfix release are considered to be fixes, not additional features.
Beside backward-compatible modifier- and override-fixes, the release includes these API additions:
TreeMap/TreeSet.collector()
do explicitly enforce that the key/element-type is Comparable. We did this by narrowing a generic parameter. However, the previous version would have lead to a ClassCastException at runtime if the given type were not Comparable.
interface javaslang.collection.Iterator<T> {
+ static Iterator<BigDecimal> rangeBy(BigDecimal from, BigDecimal toExclusive, BigDecimal step)
}
class javaslang.collection.TreeMap<K, V> {
~ static <K extends Comparable<? super K>, V> Collector<Tuple2<K, V>, ArrayList<Tuple2<K, V>>, TreeMap<K, V>> collector()
+ static <K, V> Collector<Tuple2<K, V>, ArrayList<Tuple2<K, V>>, TreeMap<K, V>> collector(Comparator<? super K> keyComparator)
}
class javaslang.collection.TreeSet<T> {
~ static <T extends Comparable<? super T>> Collector<T, ArrayList<T>, TreeSet<T>> collector()
+ static <T> Collector<T, ArrayList<T>, TreeSet<T>> collector(Comparator<? super T> comparator)
}
Behavioral Changes
Iterator.rangeBy/rangeClosedBy
internally now use BigDecimal instead of double to calculate the range (see #1309).Traversable.dropWhile/takeWhile/span
behaved incorrect. This is fixed now (see #1641).LinkedHashMap.values()
does now preserve insertion order (see #1656).Value.toCharSeq()
now returns a string representation of the contained element(s) instead of the container type (see #1685).Traversable.min()/max()
throw now NullPointerException in each case if a null element exists (see #1482).
List of Changes
Bugfixes
«base»
«collections»
- PR #1695 (fixes #1549) Re-worked TreeMap comparators, considering null-keys
→ 2767cf - PR #1692 (fixes #1482) min() max() now throw NPE on null values
→ 5326c88, 7c2c906 - PR #1671 (fixes #1633) use a Vector as accumulator of map.traverse
→ 662cdd7 - PR #1657 (fixes #1656) Fixes LinkedHashMap::values()
→ 6466e98 - PR #1646 (fixes #1641) Fixes truncation bug of dropWhile and null handling of takeWhile and dropWhile
→ 6b6d40e - PR #1308 (fixes #1309) Iterator range maintenance
→ cc48033 - PR #1251 (fixes #1249) Map/Set factories with comparator
→ f3f8f99
Improvements
«collections»
Documentation
«control»
Bugfix Release 2.0.4
Committers
@danieldietrich
@jorander
@mvh77
@paplorinc
@ruslansennov
New and Noteworthy
API Additions
Javaslang follows the semantic versioning scheme. In the strict sense API additions require a minor version update. However, the additions that are contained in this bugfix release are considered to be fixes, not additional features.
Beside backward-compatible modifier- and override-fixes, the release includes these API additions:
class javaslang.Lazy<T> {
+ static <T> Lazy<T> narrow(Lazy<? extends T> lazy)
}
class javaslang.collection.CharSeq {
+ interface CharUnaryOperator {
char apply(char c)
}
+ interface CharFunction<R> {
R apply(char c)
}
}
class javaslang.control.Option<T> {
+ static <T> Option<T> when(boolean condition, T value)
}
Behavioral Changes
Option.when(boolean, Supplier)
returnsSome(null)
instead ofNone
if theSupplier
returnsnull
.Validation.valid(null)
does returnValid(null)
instead of throwing aNullPointerException
.LinkedHashMap.replace(Tuple2, Tuple2)
replaces a pair (if exists) and preserves its position instead of appending it.LinkedHashSet.replace(T, T)
replaces an element (if exists) and preserves its position instead of appending it.
List of Changes
Bugfixes
- PR #1269 (fixes #1272) Fixed
Option.when
in case of a nullable supplier
→ 7e1e7f9, b7be4fc - PR #1297 SortedSet.unzip3 overridden
→ 796dfe0, c766726 - PR #1390 (fixes #1388) Pattern-match generator should use full class names in generated code
→ 84c6f15 - PR #1400 (fixes #1377) Added a few methods to the public API of collections
→ 3bff648 - PR #1419 Iterator#iterate should not call supplier function until value is really needed
→ 3d76301, f369a5c - PR #1420 Fix TreeMap creation from Java Map
→ 9358416, 8337cc8 - PR #1512 (fixes #1326) Replaces AbstractMap with Maps.
→ c1f4d98, baf1659 - PR #1586 (fixes #1585) Taking primitive types into account when converting to Java array.
→ bfb7063 - PR #1587 NullPointer Exception could occur on equals call.
→ 100cce9 - PR #1597 Fixes problem with null-keys in LinkedHashMap put() and remove()
→ 7ea1ae4 - PR #1598 Fixed exception messages in Array
→ 9d5ac62 - PR #1601 (fixes #1599) Fixes LinkedHashMap/LinkedHashSet replace() methods
→ 7d7712e
Improvements
- PR #1242 (fixes #1235) better equals/hashcode impls
→ fbfe9f9, b4c8c56 - PR #1247 (fixes #1243) LeafSingleton: compare hashCodes before checking equality
→ 9c2fbd2 - PR #1350 (fixes #1345) Optimized
groupBy
operations
→ 21c901b, 6d70844, 0a7e912, 0f1bf89 - PR #1357 makes HAMT iteration 10x faster
→ 49a9aa6, e1235db, 6104935 - PR #1567 Optimized usage of double-check idiom
→ 9868a9e - PR #1571 further improvement of Lazy.get()
→ 3b8171e - PR #1577
Lazy
access minor speedup
→ 743cb07 - PR #1588 Allow Validation.valid(null)
→ 5747633 - PR #1595 Try$NonFatal.of is not intended to be public
→ 6863cff - PR #1596 Re-added Traversable.hash in order to stay backward compatible
→ b67699a
Documentation
Bugfix Release 2.0.3
- 1dd090a Fixes escaping RejectedExecutionException in Future
Bugfix Release 1.2.3
- Fixed #1366