Functional
Functional programming for Java. Enhanced switch or simple pattern matching supported; String Interpolation supported; Java Functional Interface that more simpler and easier to use; Provide an immutable and thread-safe date time class; a stopwatch utility class, etc. 提供更简单更好用的Java函数式编程接口、增强版switch、字符串插值;提供不可变且线程安全的时间类、秒表工具类等等。且兼容Java8与Java9模块化系统
Install / Use
/learn @io-fairy/FunctionalREADME
English | 简体中文
Functional is a powerful Java utility library providing various functional programming tools:
- 🔥 Provides simpler and better Java functional programming interfaces
- 🔥 Enhanced switch statement (simple pattern matching support)
- 🔥 String interpolation (
SI) - 🔥
Tupletype support - 🕒 <u>Immutable and thread-safe</u>
DateTimeutility class with unified temporal API- 🔺 Powerful datetime API
- Automatic parsing of multiple datetime formats
- Time unit-based rounding operations (round, ceil, floor)
- Temporal offset calculations
- Temporal Interval calculations
- Custom datetime formatting
- Week information retrieval and formatting
- Conversion between temporal types
- 🔺 Supports multiple temporal types:
Date,Calendar,LocalDateTime,ZonedDateTime,OffsetDateTime,Instant,LocalDate
- 🔺 Powerful datetime API
- 🕒 Convenient
Stopwatchutility for benchmarking code execution times - 💡 Compatibility with Java 8+ and Java 9+ module systems
- ...
🗺️ Overview
- 📘Enhanced Switch (Pattern Matching)
- 🔥String Interpolator
- 📘Functional Interfaces
- 📘Tuple
- 🕒Powerful Temporal API
- 🕒Stopwatch
- 📝Swagger Configuration for
DateTimeandRange
🚀Quick Start
🛠️Environment
- JDK 9.0.4 (Compatibility with Java 8+ and Java 9+ module systems)
- Apache maven 3.6.1
💿 Integration
Maven
<dependency>
<groupId>com.iofairy</groupId>
<artifactId>functional</artifactId>
<version>0.6.1</version>
</dependency>
Gradle
implementation 'com.iofairy:functional:0.6.1'
📘Enhanced Switch (Pattern Matching)
Enhanced switch supports:
- Traditional switch-compatible types (
byte,short,char,int,enum,String) - Arbitrary type matching
- Object type checks (replaces
instanceof) - Conditional branching (replaces
if-else)
Object Value Matching
For value equality checks (requires static import: import static com.iofairy.pattern.Pattern.*;)
- Value-returning pattern matching
import static com.iofairy.pattern.Pattern.*;
String s = "5";
// with return value
String result = match(s)
.when("1", v -> v + v)
.when("2", v -> v + "a")
.when(in("3", "4", "5", "6"), v -> v + " - abcd") // The in() is used to match multiple values at once.
.orElse(v -> "no match");
/*
* it is equivalent to the code below.
*/
String switchResult;
switch (s) {
case "1":
switchResult = s + s;
break;
case "2":
switchResult = s + "a";
break;
case "3":
case "4":
case "5":
case "6":
switchResult = s + " - abcd";
break;
default:
switchResult = "no match";
}
- Void-returning pattern matching
import static com.iofairy.pattern.Pattern.*;
int i = 10;
// returns null
Void nullValue = match(i)
.when(1,
/*
* if you want to match `when(V matchValue, V1<V> action)` not `when(V matchValue, R1<V, R> action)`,
* you need add `{ }`, see: void-compatible and value-compatible
*/
v -> { System.out.println("match value:" + v); }) // add {} to void-compatible.
.whenNext(10,
v -> System.out.println("match value:" + v + " whenNext continue..."))
.when(20,
v -> System.out.println("match value:" + v))
.orElse(
v -> System.out.println("--orElse--"));
/*
* output:
* match value:10 whenNext continue...
* --orElse--
*/
🔔️Note: Lambda expressions void-compatible or value-compatible。
Null Value Handling
Can match null values, eliminating the need for verbose null checks like:if(xxx == null){...} else {...}
🔔️ Recommendation: Prioritize null matching to prevent NullPointerException - if a variable is null, subsequent branches are skipped automatically.
import static com.iofairy.pattern.Pattern.*;
String s = null;
String strResult1 = match(s)
// Avoid "Ambiguous method call", if you want to match `null` value, you need use `(String) null` or in(null)
.when((String) null, v -> "string null value")
.when("abcd", v -> "is not null")
.orElse(v -> "other value");
assertEquals("string null value", strResult1);
String strResult2 = match(s)
.when(in(null), v -> "contains null value")
.when("abcd", v -> "is not null")
.orElse(v -> "other value");
assertEquals("contains null value", strResult2);
String strResult3 = match(s)
.when(in("a", "b", null, "c"), v -> "contains null value")
.when("abcd", v -> "is not null")
.orElse(v -> "other value");
assertEquals("contains null value", strResult3);
Tuple2<String, Integer> t2 = null;
String classMatch = match(t2, TYPE)
.when(Integer.class, v -> "integer class")
.when(null, v -> "value is null: " + v)
.when(Tuple2.class, v -> "tuple2 class")
.orElse(v -> "other class");
assertEquals("value is null: " + null, classMatch);
String res = match(null, VALUE)
.when(null, v -> "null value")
.orElse(v -> "other value");
assertEquals("null value", res);
Type-based Matching
import static com.iofairy.pattern.Pattern.*;
Object o = Tuple.of("zs", 20);
// add `TYPE` to match Class<?>.
Integer result = match(o, TYPE)
.when(Integer.class, v -> v + 10)
.when(Tuple2.class, v -> v.arity())
.when(String.class, v -> v.contains("abc") ? 20 : 30)
.orElse(v -> 40);
/*
* it is equivalent to the code below.
*/
Integer ifResult;
if (o instanceof Integer) {
ifResult = (Integer) o + 10;
} else if (o instanceof Tuple2) {
ifResult = ((Tuple2) o).arity();
} else if (o instanceof String) {
ifResult = ((String) o).contains("abc") ? 20 : 30;
} else {
ifResult = 40;
}
String Pattern Matching
import static com.iofairy.pattern.Pattern.*;
String str = "aBcdE123.$fGHIj";
// ignore case match
String matchRes1 = match(str, IGNORECASE)
.when((String) null, v -> "match null")
.when("abcd", v -> "match abcd")
.when("abcde123.$fGHIj", v -> "ignore case match")
.orElse(v -> "no match");
assertEquals("ignore case match", matchRes1);
// CONTAIN match
String matchRes2 = match(str, CONTAIN)
.when("abcd", v -> "abcd")
.when("E123", v -> "E123")
.orElse(v -> "no match");
assertEquals("E123", matchRes2);
// ignore case for contain
String matchRes3 = match(str, ICCONTAIN)
.when("abcd1", v -> "abcd1")
.when(in(null, "aaa", ".$fghi", "123"), v -> ".$fghi")
.orElse(v -> "no match");
assertEquals(".$fghi", matchRes3);
// PREFIX
String matchRes4 = match(str, PREFIX)
.when("abcd", v -> "abcd")
.when("aBcd", v -> "aBcd")
.orElse(v -> "no match");
assertEquals("aBcd", matchRes4);
// ignore case for suffix
String matchRes5 = match(str, ICSUFFIX)
.when("fghij", v -> "fGHIj")
.when("aBcd", v -> "aBcd")
.orElse(v -> "no match");
assertEquals("fGHIj", matchRes5);
Conditional Matching (alternative to if-else)
import static com.iofairy.pattern.Pattern.*;
int i = 10;
String result = match()
.when(i == 0,
v -> "i is zero")
.when(i < 5 && i > 0,
v -> "i is between 0~5")
.when(i > 5,
v -> "i is greater than 5")
.orElse(v -> "i is equals to: " + v);
System.out.println("match result:" + result);
/*
* it is equivalent to the code below
*/
String ifResult;
if (i == 0) {
ifResult = "i is zero";
} else if (i < 5 && i > 0) {
ifResult = "i is between 0~5";
} else if (i > 5) {
ifResult = "i is greater than 5";
} else {
ifResult = "i is equals to: " + i;
}
🔥String Interpolator
What can do?
Replaces cumbersome + concatenation and Java's built-in interpolators (MessageFormat.format() or String.format())
- Built-in Java
int id = 12345;
String name = "zhangsan";
float height = 180.5f;
// use `+` concatenation
String res1 = "id: " + id + " 名字:" + name + " 身高(cm): " + height;
System.out.println(res1);
// use MessageFormat.format
String res2 = MessageFormat.format("id: {0} 名字:{1} 身高(cm): {2}", id, name, height);
System.out.println(res2);
// use String.format
String res3 = String.format("id: %d 名字:%s 身高(cm): %.1f", id, name, height);
System.out.println(res3);
- **use string in
