diff --git a/README.md b/README.md
index d4cfe6fbe9532ea97b2256b5a4ff8f8956749010..9456efab49e69645a45f9ec3831937026bccb82d 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ To build the Prolog binaries you require a SICStus 4 (http://sicstus.sics.se/ind
 - We use gradle to manage the dependencies to the libraries, thus you will need gradle installed on your computer.
   (see http://www.gradle.org/)
 
-- In the workspace directory run the completeInstall task (```gradle completeInstall```), alternatively you can also run the downloadCli and collectDependencies tasks (```gradle downloadCli collectDependencies```). This will download the latest nightly build of the Prolog binary and the required Java libraries (such as apache commons, etc.)
+- In the workspace directory run the completeInstall task (```gradle completeInstall```), alternatively you can also run the downloadCli and collectDependencies tasks (```gradle downloadCli collectDependencies```). This will download the latest nightly build of the Prolog binary and the required Java libraries (such as the parser libraries).
 
 - Install Eclipse for RCP Development
 
diff --git a/build.gradle b/build.gradle
index 90dbcc0c8805c5c5c5a392bf6823322220893a2a..51af8611124bb7ce4ccfc868da0df4112c3684e8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -38,7 +38,6 @@ project(':de.prob.core') {
 		implementation group: "de.hhu.stups", name: "prologlib", version: parser_version
 		implementation group: "de.hhu.stups", name: "unicode", version: parser_version
 		implementation group: "de.hhu.stups", name: "theorymapping", version: parser_version
-		implementation 'commons-lang:commons-lang:2.6'
 		implementation 'com.thoughtworks.xstream:xstream:1.4.19'
 		// Current versions of XStream depend on MXParser, but not any specific version of it.
 		// To avoid the version number changing unexpectedly and breaking the MANIFEST.MF classpath entries,
diff --git a/de.prob.core/.classpath b/de.prob.core/.classpath
index 2966915c3e3940675801591bd0d1a3c3fcd8f241..bc5c8d8ef71eef1c0c746a7502ec7651765b3f1d 100644
--- a/de.prob.core/.classpath
+++ b/de.prob.core/.classpath
@@ -10,7 +10,6 @@
 	-->
 	<classpathentry exported="true" kind="lib" path="lib/dependencies/answerparser-2.12.4.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/dependencies/bparser-2.12.4.jar"/>
-	<classpathentry exported="true" kind="lib" path="lib/dependencies/commons-lang-2.6.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/dependencies/jna-3.4.0.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/dependencies/jsr305-1.3.9.jar"/>
 	<classpathentry exported="true" kind="lib" path="lib/dependencies/ltlparser-2.12.4.jar"/>
diff --git a/de.prob.core/META-INF/MANIFEST.MF b/de.prob.core/META-INF/MANIFEST.MF
index b58a587fe9433899a58102254213d8cc92978586..afbb3c92a4105332b768034b58a68c7da2148296 100644
--- a/de.prob.core/META-INF/MANIFEST.MF
+++ b/de.prob.core/META-INF/MANIFEST.MF
@@ -97,15 +97,6 @@ Export-Package: com.thoughtworks.xstream,
  javax.annotation,
  javax.annotation.concurrent,
  javax.annotation.meta,
- org.apache.commons.lang,
- org.apache.commons.lang.builder,
- org.apache.commons.lang.enums,
- org.apache.commons.lang.exception,
- org.apache.commons.lang.math,
- org.apache.commons.lang.mutable,
- org.apache.commons.lang.reflect,
- org.apache.commons.lang.text,
- org.apache.commons.lang.time,
  org.ptolemy.fmi,
  org.ptolemy.fmi.driver,
  org.ptolemy.fmi.type
@@ -123,7 +114,6 @@ Bundle-ClassPath: .,
  lib/dependencies/answerparser-2.12.4.jar,
  lib/dependencies/ptolemy-jfmi-1.1.0.jar,
  lib/dependencies/xstream-1.4.19.jar,
- lib/dependencies/commons-lang-2.6.jar,
  lib/dependencies/jsr305-1.3.9.jar,
  lib/dependencies/mxparser-1.2.2.jar,
  lib/dependencies/xmlpull-1.1.3.1.jar,
diff --git a/de.prob.core/src/de/prob/core/ProblemHandler.java b/de.prob.core/src/de/prob/core/ProblemHandler.java
index 95d05d591be576cce97080480d1331813d30e5e5..7a269ea4cd37c9cef509740474908f3b2e6e50dc 100644
--- a/de.prob.core/src/de/prob/core/ProblemHandler.java
+++ b/de.prob.core/src/de/prob/core/ProblemHandler.java
@@ -8,8 +8,6 @@ package de.prob.core;
 
 import java.util.List;
 
-import org.apache.commons.lang.StringUtils;
-
 import de.prob.cli.CliException;
 import de.prob.core.command.CommandException;
 import de.prob.core.internal.ResultParserException;
@@ -69,7 +67,7 @@ public class ProblemHandler {
 	public static void raisePrologException(final List<String> errors,
 			final boolean onlyWarnings) throws PrologException {
 		final String message = "ProB reported errors:\n"
-				+ StringUtils.join(errors, '\n');
+				+ String.join("\n", errors);
 		Logger.notifyUser(message);
 		throw new PrologException(message, onlyWarnings);
 	}
diff --git a/de.prob.core/src/de/prob/core/command/ComposedCommand.java b/de.prob.core/src/de/prob/core/command/ComposedCommand.java
index a77db17b2c77e5f6ddd4c13745eefeddab5e995d..34c98a1f3110dca746719f754ad2fff1b2226726 100644
--- a/de.prob.core/src/de/prob/core/command/ComposedCommand.java
+++ b/de.prob.core/src/de/prob/core/command/ComposedCommand.java
@@ -5,8 +5,6 @@ package de.prob.core.command;
 
 import java.util.List;
 
-import org.apache.commons.lang.ArrayUtils;
-
 import de.prob.parser.ISimplifiedROMap;
 import de.prob.prolog.output.IPrologTermOutput;
 import de.prob.prolog.output.PrologTermDelegate;
@@ -77,14 +75,14 @@ public class ComposedCommand implements IComposableCommand {
 	public void reprocessResult(final IComposableCommand command,
 			final ISimplifiedROMap<String, PrologTerm> bindings)
 			throws CommandException {
-		final int index = ArrayUtils.indexOf(cmds, command);
-		if (index >= 0) {
-			final PrefixMap<PrologTerm> prefixMap = new PrefixMap<PrologTerm>(
-					bindings);
-			processPrefixedCommand(prefixMap, index);
-		} else
-			throw new IllegalArgumentException(
-					"cannot reprocess command, command unknown");
+		for (int i = 0; i < cmds.length; i++) {
+			if (command.equals(cmds[i])) {
+				final PrefixMap<PrologTerm> prefixMap = new PrefixMap<PrologTerm>(bindings);
+				processPrefixedCommand(prefixMap, i);
+				return;
+			}
+		}
+		throw new IllegalArgumentException("cannot reprocess command, command unknown");
 	}
 
 	/**
diff --git a/de.prob.core/src/de/prob/core/domainobjects/Operation.java b/de.prob.core/src/de/prob/core/domainobjects/Operation.java
index 0e3d1be0dc41d27d93cafb64b342210cc2368eca..16c341bb60471dd9c0fba1595ec8c7c77d90ff46 100644
--- a/de.prob.core/src/de/prob/core/domainobjects/Operation.java
+++ b/de.prob.core/src/de/prob/core/domainobjects/Operation.java
@@ -12,8 +12,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.lang.StringUtils;
-
 import de.prob.prolog.term.CompoundPrologTerm;
 import de.prob.prolog.term.IntegerPrologTerm;
 import de.prob.prolog.term.ListPrologTerm;
@@ -289,7 +287,7 @@ public final class Operation {
 		if (argsPretty.isEmpty()) {
 			return name;
 		} else {
-			return name + "(" + StringUtils.join(argsPretty, ',') + ")";
+			return name + "(" + String.join(",", argsPretty) + ")";
 		}
 	}
 
diff --git a/de.prob.core/src/de/prob/core/domainobjects/Variable.java b/de.prob.core/src/de/prob/core/domainobjects/Variable.java
index a7d2bd234065a16f1002f949c2e0fc5696012a3e..74a4a30af254c755228467b434db6a701e37cc20 100644
--- a/de.prob.core/src/de/prob/core/domainobjects/Variable.java
+++ b/de.prob.core/src/de/prob/core/domainobjects/Variable.java
@@ -6,7 +6,7 @@
 
 package de.prob.core.domainobjects;
 
-import org.apache.commons.lang.ObjectUtils;
+import java.util.Objects;
 
 import de.prob.core.command.CommandException;
 import de.prob.parser.BindingGenerator;
@@ -94,7 +94,7 @@ public final class Variable {
 		} else if (obj != null && obj instanceof Variable) {
 			Variable other = (Variable) obj;
 			equal = this.identifier.equals(other.identifier)
-					&& ObjectUtils.equals(this.value, other.value);
+					&& Objects.equals(this.value, other.value);
 		} else {
 			equal = false;
 		}
diff --git a/de.prob.core/src/de/prob/core/langdep/EventBAnimatorPart.java b/de.prob.core/src/de/prob/core/langdep/EventBAnimatorPart.java
index 214b4dbb6a6991b71d5134711405567e6411b7d6..ce5c43bbe88897436291d44ce685366271618d06 100644
--- a/de.prob.core/src/de/prob/core/langdep/EventBAnimatorPart.java
+++ b/de.prob.core/src/de/prob/core/langdep/EventBAnimatorPart.java
@@ -6,9 +6,9 @@ package de.prob.core.langdep;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
-import org.apache.commons.lang.ObjectUtils;
 import org.eclipse.core.runtime.CoreException;
 import org.eventb.core.IContextRoot;
 import org.eventb.core.IEventBRoot;
@@ -187,7 +187,7 @@ public class EventBAnimatorPart implements LanguageDependendAnimationPart {
 		final ISCMachineRoot machine = ((IMachineRoot) root).getSCMachineRoot();
 		try {
 			for (final ISCEvent event : machine.getSCEvents()) {
-				if (ObjectUtils.equals(event.getLabel(), eventName))
+				if (Objects.equals(event.getLabel(), eventName))
 					return event;
 			}
 			throw new ProBParseException("unknown event " + eventName);
diff --git a/de.prob.core/src/de/prob/eventb/translator/ContextTranslator.java b/de.prob.core/src/de/prob/eventb/translator/ContextTranslator.java
index 578a2746ae11a67f780c9727e7151d4dc06fd248..8fa94a5de2e41f821f52d679f6f7ee00ded78da1 100644
--- a/de.prob.core/src/de/prob/eventb/translator/ContextTranslator.java
+++ b/de.prob.core/src/de/prob/eventb/translator/ContextTranslator.java
@@ -13,7 +13,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.lang.StringUtils;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
 import org.eventb.core.IContextRoot;
@@ -218,7 +217,7 @@ public final class ContextTranslator extends AbstractComponentTranslator {
 
 		if (!bugs.isEmpty()) {
 			String message = "Translation incomplete due to a Bug in Rodin. This does not affect correctness of the Animation/Model Checking but can decrease its performance. Skipped discharged information about: "
-					+ StringUtils.join(bugs, ",");
+					+ String.join(",", bugs);
 			Logger.notifyUser(message);
 		}
 
diff --git a/de.prob.core/src/de/prob/eventb/translator/internal/ModelTranslator.java b/de.prob.core/src/de/prob/eventb/translator/internal/ModelTranslator.java
index b25225cfb42ef06fe6b10d5109facf48edd1e5be..3bf6a9449c210a2206f817d7ec11b80710a644f1 100644
--- a/de.prob.core/src/de/prob/eventb/translator/internal/ModelTranslator.java
+++ b/de.prob.core/src/de/prob/eventb/translator/internal/ModelTranslator.java
@@ -12,7 +12,6 @@ import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
-import org.apache.commons.lang.StringUtils;
 import org.eclipse.core.runtime.CoreException;
 import org.eventb.core.IConvergenceElement.Convergence;
 import org.eventb.core.ILabeledElement;
@@ -237,7 +236,7 @@ public class ModelTranslator extends AbstractComponentTranslator {
 
 		if (!bugs.isEmpty()) {
 			String message = "Translation incomplete due to a Bug in Rodin. This does not affect correctness of the Animation/Model Checking but can decrease its performance. Skipped discharged information about: "
-					+ StringUtils.join(bugs, ",");
+					+ String.join(",", bugs);
 			Logger.notifyUser(message);
 		}
 
diff --git a/de.prob.ui/src/de/prob/ui/historyview/HistoryView.java b/de.prob.ui/src/de/prob/ui/historyview/HistoryView.java
index b6dd099a042da661381d6295ff864e791e9fccd5..74eded7bc6fb388117f2411ad3c2b3c53b243088 100644
--- a/de.prob.ui/src/de/prob/ui/historyview/HistoryView.java
+++ b/de.prob.ui/src/de/prob/ui/historyview/HistoryView.java
@@ -4,10 +4,12 @@
 package de.prob.ui.historyview;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.ObjectUtils;
 import org.eclipse.jface.layout.TableColumnLayout;
 import org.eclipse.jface.viewers.ColumnWeightData;
 import org.eclipse.jface.viewers.DoubleClickEvent;
@@ -168,15 +170,17 @@ public class HistoryView extends StateBasedViewPart {
 		final Animator animator = Animator.getAnimator();
 		MachineDescription machineDescription = animator
 				.getMachineDescription();
-		String[] models = new String[0];
+		List<String> models;
 		if (machineDescription != null) {
-			models = machineDescription.getModelNames().toArray(new String[0]);
-			ArrayUtils.reverse(models);
+			models = new ArrayList<>(machineDescription.getModelNames());
+			Collections.reverse(models);
+		} else {
+			models = Collections.emptyList();
 		}
 		final TableColumnLayout layout = new TableColumnLayout();
 		composite.setLayout(layout);
 		labelProviders = new ArrayList<HistoryLabelProvider>();
-		if (models.length > 0) {
+		if (!models.isEmpty()) {
 			int pos = 0;
 			for (final String model : models) {
 				final boolean isFirst = pos == 0;
@@ -227,7 +231,7 @@ public class HistoryView extends StateBasedViewPart {
 				vItems[i] = new HistViewItem(i, activeItem, state, op, cs);
 			}
 			current = vItems[activeItem];
-			ArrayUtils.reverse(vItems);
+			Collections.reverse(Arrays.asList(vItems));
 		} else {
 			current = null;
 		}
@@ -256,10 +260,8 @@ public class HistoryView extends StateBasedViewPart {
 			// The item representing the root state has no operation leading to
 			// it, so we have to check if it is null
 			this.previousStateIsSameAsCurrent = operation != null
-					&& ObjectUtils.equals(currentState.getId(),
-							operation.getSource());
-			this.followingStateIsSameAsCurrent = ObjectUtils.equals(
-					currentState, dstState);
+					&& Objects.equals(currentState.getId(), operation.getSource());
+			this.followingStateIsSameAsCurrent = Objects.equals(currentState, dstState);
 		}
 
 		public State getDestination() {
diff --git a/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeExpression.java b/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeExpression.java
index b5e5d24d74eaf0d774c4b014b0d4f1a48ff654bd..cca8adeb32d73216c60f35c6d41b4e0c0d18d863 100644
--- a/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeExpression.java
+++ b/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeExpression.java
@@ -6,8 +6,7 @@ package de.prob.ui.stateview.statetree;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-
-import org.apache.commons.lang.ObjectUtils;
+import java.util.Objects;
 
 import de.prob.core.command.EvaluationGetValuesCommand;
 import de.prob.core.command.EvaluationGetValuesCommand.EvaluationResult;
@@ -78,7 +77,7 @@ public class StateTreeExpression extends AbstractStateTreeElement {
 			e.notifyUserOnce();
 			return false;
 		}
-		return !ObjectUtils.equals(curval, lastval);
+		return !Objects.equals(curval, lastval);
 	}
 
 	private String getResultString(final State state) throws ProBException {
diff --git a/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeVariable.java b/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeVariable.java
index ee019d7036c51b812dbba92911f21b209cd125d3..d83d76b0598ee5f69ab5aa2c1b6d7f1e89602709 100644
--- a/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeVariable.java
+++ b/de.prob.ui/src/de/prob/ui/stateview/statetree/StateTreeVariable.java
@@ -3,7 +3,7 @@
  */
 package de.prob.ui.stateview.statetree;
 
-import org.apache.commons.lang.ObjectUtils;
+import java.util.Objects;
 
 import de.prob.core.domainobjects.State;
 import de.prob.core.domainobjects.Variable;
@@ -45,7 +45,7 @@ public class StateTreeVariable extends AbstractStateTreeElement {
 	public boolean hasChanged(final State current, final State last) {
 		final String curVal = getValueOfVar(current);
 		final String lastVal = getValueOfVar(last);
-		return !ObjectUtils.equals(curVal, lastVal);
+		return !Objects.equals(curVal, lastVal);
 	}
 
 	private String getValueOfVar(final State state) {