Skip to content

Releases: vavr-io/vavr

Bugfix Release 0.9.2

24 Nov 21:44
Compare
Choose a tag to compare

Contributors

Daniel Dietrich
Erlend Hamnaberg
Michael Ummels
Pap Lőrinc
Robert Erdin
Valeriy Vyrva

Changelog

Works fine on JDK 9

Vavr 0.9.2 now works fine on JDK 9. The previous release 0.9.1 had an internal dependency that broke the JDK 9 build - we fixed that.

Note: JDK 9 introduced a type inference bug that may affect Vavr's pattern matching in some cases. Please see JDK-8039214.

Collections

  • We fixed the implementation of Multimap.last(). We did not override the default Traversable implementation.
  • We fixed a problem with the intersection of ordered collections that are based on RedBlackTree (such as TreeSet).

Concurrent

  • We fixed Future.traverse(ExecutorService, Iterable, Function). The ExecutorService was not taken into account.

More fixes...

  • Beside the above, we fixed some javadoc typos.

Please find the complete list of changes here.

Bugfix Release 0.9.1

17 Sep 19:59
Compare
Choose a tag to compare

Contributors

Christian Bongiorno
Daniel Dietrich
Emmanuel Touzery
Julien Debon
Nazarii Bardiuk
Pascal Schumacher
Ruslan Sennov

Changelog

Concurrent operations

  • We fixed a bug that prevented onFailure actions to be performed when a Future has been cancelled.
  • There are known problems with Promise that occur under certain circumstances (see details below). Please note that we did not fix this problem in 0.9.1. We currently work on it in #2093.

The main thread may be blocked forever if we use an operation that blocks on a Future returned by a Promise. We observed this behavior when we used a ForkJoinPool instead of the default CachedThreadPool.

Example:

// we choose a work-stealing thread pool
ExecutorService executor = java.util.concurrent.ForkJoinPool.commonPool();
Future<Object> someFuture = Future.of(executor, () -> longRunningTask());

// the internal Future of a Promise might deadlock the system if we block on that Future
Promise<Object> promise = Promise.make(executor);
someFuture.onComplete(promise::complete);

// the bug only shows up when calling a blocking operation, like get() or isEmpty()
Object result = promise.future().get();

Numeric operations

  • Removed the Traversable.min(), max() overloads TreeSet.min() and TreeSet.max()
  • Made Traversable.average(), sum() and product() more accurate.

TreeSet min()/max()

TreeSet implements SortedSet, which represents distinct elements that are ordered using a specific Comparator.
By default, Traversable.min() and max() calculate the minimum resp. maximum element in linear time O(n) using the natural element order.
However, we used the TreeSet collection characteristic to calculate the min() / max() in constant time O(1).

This was wrong for two reasons:

  1. The Traversable API spec states that min() and max() are calculated using the natural element order. This has to be the case because of the Liskov substitution principle, see examples below.
  2. The minimum of any non-empty collection containing double values is Double.NaN if one or more elements are NaN. But the natural Comparator of Double is defined in the way that NaN >= d for every double d.

Example:

// = TreeSet(3, 2, 1)
Set<Integer> ints = TreeSet.of(Comparator.reverseOrder(), 1, 2, 3);

// = 3 (before), = 1 (after)
ints.min();

// = 1 (before), = 3 (after)
ints.max();

// = List(1.0, NaN, 3.0)
List<Integer> doubles = List.of(1.0, Double.NaN, 3.0);

// = 1.0 (before), = NaN (after)
doubles.min();

// = NaN (both ok, before and after this change)
doubles.max();

Traversable average(), sum() and product()

sum() and product() operate on elements of type Number. Now we return a Number according to the input argument or fallback to double.

sum() and average() now internally use an improved summation compensation algorithm that fixes problems that occur in standard Java.

Example:

// = OptionalDouble(0.0) (wrong)
j.u.s.DoubleStream.of(1.0, 10e100, 2.0, -10e100).average()

// = Some(0.75) (correct)
List.of(1.0, 10e100, 2.0, -10e100).average()

Missing methods

We added

  • Either.sequence(Iterable<? extends Either<? extends L, ? extends R>>)
  • Either.sequenceRight(Iterable<? extends Either<? extends L, ? extends R>>)

Examples:

// = Right(List(all, right)) of type Either<Seq<Integer>, Seq<String>> 
Either.sequence(List.of(Either.right("all"), Either.right("right")));

// = Left(List(1, 2)) of type Either<Seq<Integer>, Seq<String>> 
Either.sequence(List.of(Either.left(1), Either.left(2), Either.right("ok")));

// = Right(List(all, right)) of type Either<Integer, Seq<String>> 
Either.sequenceRight(List.of(Either.right("all"), Either.right("right")));

// = Left(1) of type Either<Integer, Seq<String>> 
Either.sequenceRight(List.of(Either.left(1), Either.left(2), Either.right("ok")));

Type narrowing

We changed the generic bounds of these method arguments:

  • Function0<R>.narrow(Function0<? extends R>) (before: narrow(Supplier<? extends R>))
  • Function1<T1, R> Function1.narrow(Function1<? super T1, ? extends R>) (before: narrow(Function<? super T1, ? extends R>))
  • Function2<T1, T2, R> Function2.narrow(Function2<? super T1, ? super T2, ? extends R>) (before: narrow(BiFunction<? super T1, ? super T2, ? extends R>))

Background: Java is not able to do the following type assignment:

M<? extends T> m = ...;
M<T> narrowed = m; // does not work but it is correct for immutable objects.

Therefore almost all Vavr types have narrow methods.

M<? extends T> m = ...;
M<T> narrowed = M.narrow(m); // works as expected

GWT compatibility fixes

The following methods were annotated with @GwtIncompatible:

  • Predicates#instanceOf(Class)
  • asJava(), asJava(Consumer), asJavaMutable(), asJavaMutable(Consumer) of io.vavr.collection.Seq and all its subtypes,
    namely IndexedSeq, LinearSeq, Array, CharSeq, List, Queue, Stream and Vector

Documentation

We added more examples and improved the readability of the Javadoc:

javadoc

Thanks to Stuart Marks, he was so kind to initiate an issue in order to improve the default Javadoc style.

You find the Vavr 0.9.1 API specification here.

More fixes...

  • We removed internal memoization of sortBy() in order to fix an issue with lazy collections that have infinite size
  • We optimized collection conversion
  • We fixed the generics of Multimap builders
  • We improved Traversable.reduceLeft
  • We improved Iterator.dropWhile and slideBy

Please find the complete list of changes here.

Major Release 0.9

16 May 22:09
Compare
Choose a tag to compare

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 of toOption() (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) by toJavaList(Function)
    • toJavaSet(Supplier) by toJavaSet(Function)
  • We added introspection methods isAsync() and isLazy() that provide information about a Value type at runtime
  • We added getOrNull() which returns null if the Value 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.λ to io.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 to io.vavr.
  • We replaced the functional interface Try.CheckedSupplier by the existing CheckedFunction0.

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() to apply(), e.g.
    y = f(x1, x2, x3) can be understood as y = 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:

  1. They add syntactic sugar.

E.g. instead of Try.of(() -> new Error()) we now just write Try(() -> new Error()).

  1. 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 and Try.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 to int. That strikes many methods, like take(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 and LinkedHashMultimap
  • SortedMultimap: TreeMultimap

The collections g...

Read more

Bugfix Release 2.0.6

12 May 08:38
Compare
Choose a tag to compare

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

12 May 08:38
Compare
Choose a tag to compare

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»

Improvements

«collections»

  • PR #1696 (fixes #1227) Made naturalComparator() a singleton and made use of it
    7a9cc48

Documentation

«control»

Bugfix Release 2.0.4

12 May 08:38
Compare
Choose a tag to compare

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) returns Some(null) instead of None if the Supplier returns null.
  • Validation.valid(null) does return Valid(null) instead of throwing a NullPointerException.
  • 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

Improvements

Documentation

Bugfix Release 2.0.3

12 May 08:37
Compare
Choose a tag to compare
  • 1dd090a Fixes escaping RejectedExecutionException in Future

Bugfix Release 1.2.3

12 May 08:36
Compare
Choose a tag to compare

Maintenance Release 2.0.2

12 May 08:37
Compare
Choose a tag to compare