Java Emoji (JEmoji)
JEmoji is a lightweight, fast and auto generated emoji library for Java with a complete list of all emojis from the Unicode consortium.
With many utility methods and type safe direct access to Emojis, JEmoji aims to improve your experience and development when working with Emojis.
โญ Highlights
- Extract, replace and remove emojis from text.
- Ability to detect emoji in other representations than Unicode (HTML dec / hex, url encoded).
- Auto generated type safe constant emojis are directly accessible
Emojis.THUMBS_UP
. - Get emojis dynamically with
getEmoji
,getByAlias
,getByHtmlDecimal
,getByHtmlHexadecimal
,getByUrlEncoded
. - 1 click to update the library to the newest Unicode consortium emoji specification.
โ Why another emoji library?
While several other emoji libraries for Java exist, most of them are incomplete or outdated. JEmoji, on the other hand, offers a complete list of all emojis from the Unicode Consortium, which can be generated quickly and easily with just one task. This is a major advantage over other libraries that may be no longer maintained or require extensive manual work to update their emoji lists.
In addition, the data is fetched from multiple sources to ensure that information about each emoji is enhanced as much as possible.
Fetched sources:
- unicode.org for all Unicode emojis
- Discord custom script for fetching additional information about emojis for Discord
- Slack custom script for fetching additional information about emojis for Slack
๐ฆ Installation
Replace the VERSION
with the latest version shown at the start of the README
Gradle Kotlin DSL
implementation("net.fellbaum:jemoji:VERSION")
Maven
<dependency>
<groupId>net.fellbaum</groupId>
<artifactId>jemoji</artifactId>
<version>VERSION</version>
</dependency>
๐ jemoji-language
module
The translation files for emoji descriptions and keywords are quite large (13 MB),
while the main library is optimized for minimal size (~600 KB).
To address this, a separate module, jemoji-language
,
has been introduced to provide translation files for over 160 languages as an optional dependency.
The version is always kept in sync with the main module.
Gradle Kotlin DSL
implementation("net.fellbaum:jemoji-language:VERSION")
Maven
<dependency>
<groupId>net.fellbaum</groupId>
<artifactId>jemoji-language</artifactId>
<version>VERSION</version>
</dependency>
๐ Usage
Emojis
Access any emoji directly by a constant
//Returns an Emoji instance
Emojis.THUMBS_UP;
Emojis.THUMBS_UP_MEDIUM_SKIN_TONE;
EmojiManager
Get all emojis
Set<Emoji> emojis=EmojiManager.getAllEmojis();
Get emoji by unicode string
Optional<Emoji> emoji=EmojiManager.getEmoji("๐");
Get emoji by alias
Optional<Emoji> emoji=EmojiManager.getByAlias("smile");
// or
Optional<Emoji> emoji=EmojiManager.getByAlias(":smile:");
Get all emojis by group (general category of emojis)
Set<Emoji> emojis=EmojiManager.getAllEmojisByGroup(EmojiGroup.SMILEYS_AND_EMOTION);
Get all emojis by subgroup (more specific set of emojis)
Set<Emoji> emojis=EmojiManager.getAllEmojisBySubGroup(EmojiSubGroup.ANIMAL_BIRD);
Get emojis grouped / subgrouped
//Commonly used in emoji pickers
Map<EmojiGroup, Set<Emoji>> a = EmojiManager.getAllEmojisGrouped();//{SMILEYS_AND_EMOTION=["๐","๐"...],...}
Map<EmojiSubGroup, Set<Emoji>> b = EmojiManager.getAllEmojisSubGrouped();//{FACE_SMILING=["๐","๐"...],...}
Check if the provided string is an emoji
boolean isEmoji=EmojiManager.isEmoji("๐");
Check if the provided string contains an emoji
boolean containsEmoji=EmojiManager.containsEmoji("Hello ๐ World");
Extract all emojis from a string in the order they appear
List<Emoji> emojis=EmojiManager.extractEmojisInOrder("Hello ๐ World ๐"); // [๐, ๐]
Extract all emojis from a string in the order they appear, with their found index
List<IndexedEmoji> emojis = EmojiManager.extractEmojisInOrderWithIndex("Hello ๐ World ๐");
emojis.get(0).getCharIndex(); // Prints "6"
emojis.get(0).getCodePointIndex(); // Prints "6"
emojis.get(1).getCharIndex(); // Prints "15"
emojis.get(1).getCodePointIndex(); // Prints "14"
emojis.get(0).getEmoji(); // Gets the Emoji object
Remove all emojis from a string
String text=EmojiManager.removeAllEmojis("Hello ๐ World ๐"); // "Hello World "
Remove specific emojis from a string
String text=EmojiManager.removeEmojis("Hello ๐ World ๐", Emojis.GRINNING_FACE); // "Hello World ๐"
Replace all emojis in a string
String text=EmojiManager.replaceAllEmojis("Hello ๐ World ๐","<an emoji was here>"); // "Hello <an emoji was here> World <an emoji was here>"
//or more control of the replacement with a Function that provides the emoji and wants a string as return value
String text=EmojiManager.replaceAllEmojis("Hello ๐ World ๐",Emoji::getHtmlDecimalCode); // "Hello 😀 World 👍"
Replace specific emojis in a string
String text=EmojiManager.replaceEmojis("Hello ๐ World ๐","<an emoji was here>", Emojis.GRINNING_FACE); // "Hello <an emoji was here> World ๐"
Overloaded methods with EnumSet
An additional EnumSet may be present for some methods,
which allows you to specify the appearance of an emoji which should be affected by the method.
This can be, for example, a UNICODE
emoji (๐) that is the default for all methods.
There are also HTML_DECIMAL
( 👍), HTML_HEXADECIMAL
notations and more available.
String text = EmojiManager.replaceAllEmojis("Hello ๐ World ๐ &#128077;", "<replaced>", EnumSet.of(EmojiType.HTML_DECIMAL)); // "Hello ๐ World ๐ <replaced>" -> &#128077; is the HTML character entity for the emoji ๐
Replacing aliases
String text = EmojiManager.replaceAliases(
// The text you want to process
":beach_umbrella:",
// Decide which emoji to use, as it's possible that multiple emojis share the same alias depending on which platform you are working on.
// For example, when replacing the alias ":beach_umbrella:", these two emojis will be available.
// {emoji='๐๏ธ', unicode='\uD83C\uDFD6\uFE0F', discordAliases=[:beach:, :beach_with_umbrella:], githubAliases=[:beach_umbrella:], slackAliases=[:beach_with_umbrella:], hasFitzpatrick=false, hasHairStyle=false, version=0.7, qualification=FULLY_QUALIFIED, description='beach with umbrella', group=TRAVEL_AND_PLACES, subgroup=PLACE_GEOGRAPHIC, hasVariationSelectors=false, allAliases=[:beach:, :beach_umbrella:, :beach_with_umbrella:]},
// {emoji='โฑ๏ธ', unicode='\u26F1\uFE0F', discordAliases=[:beach_umbrella:, :umbrella_on_ground:], githubAliases=[:parasol_on_ground:], slackAliases=[:umbrella_on_ground:], hasFitzpatrick=false, hasHairStyle=false, version=0.7, qualification=FULLY_QUALIFIED, description='umbrella on ground', group=TRAVEL_AND_PLACES, subgroup=SKY_AND_WEATHER, hasVariationSelectors=false, allAliases=[:beach_umbrella:, :umbrella_on_ground:, :parasol_on_ground:]}
// Note that the first contains the alias in the GitHub aliases and the 2nd in the discord aliases. The shown way of handling the choosing always picks the discord emoji.
// With this function, you can also filter for specific emojis if you want to, and in case you don't want to replace an alias, return the provided alias.
// Use this example with caution as this may not work with other aliases as this assumes that an emoji with this alias for discord exists in the list.
(alias, emojis) -> emojis.stream().filter(emoji -> emoji.getDiscordAliases().contains(alias)).findFirst().orElseThrow(IllegalStateException::new).getEmoji()
);
// Other replacements function examples:
// Replacing all discord aliases in a string with the description of an emoji, otherwise return the alias that does not exist in discord (keeping the original text).
BiFunction<String, List<Emoji>> function = (alias, emojis) -> emojis.stream().filter(emoji -> emoji.getDiscordAliases().contains(alias)).findAny().map(Emoji::getDescription).orElse(alias);
// Replacing only specific emojis with the description, otherwise return the alias (original text).
BiFunction<String, List<Emoji>> function = (alias, emojis) -> emojis.stream().filter(emoji -> Arrays.asList(Emojis.THUMBS_UP, Emojis.THUMBS_DOWN).contains(emoji)).findAny().map(Emoji::getDescription).orElse(alias);
// Replacing emojis from a specific group with the description, otherwise return the alias (original text).
BiFunction<String, List<Emoji>> function = (alias, emojis) -> emojis.stream().filter(emoji -> emoji.getGroup() == EmojiGroup.ACTIVITIES).findAny().map(Emoji::getDescription).orElse(alias);
EmojiLoader
Load all emoji keyword/description files instead of on demand
EmojiLoader.loadAllEmojiDescriptions();
EmojiLoader.loadAllEmojiKeywords();
Emoji Object
classDiagram
direction BT
class Emoji {
+ getEmoji() String
+ getUnicode() String
+ getHtmlDecimalCode() String
+ getHtmlHexadecimalCode() String
+ getURLEncoded() String
+ getVariations() List~Emoji~
+ getDiscordAliases() List~String~
+ getGithubAliases() List~String~
+ getSlackAliases() List~String~
+ getAllAliases() List~String~
+ hasFitzpatrickComponent() boolean
+ hasHairStyleComponent() boolean
+ getVersion() double
+ getQualification() Qualification
+ getDescription() String
+ getDescription(EmojiLanguage) Optional~String~
+ getKeywords() List~String~
+ getKeywords(EmojiLanguage) Optional~List~String~~
+ getGroup() EmojiGroup
+ getSubGroup() EmojiSubGroup
+ hasVariationSelectors() boolean
}
๐ Benchmarks
On every push on the master branch, a benchmark will be executed and automatically deployed to this projects GitHub pages. These benchmarks are executed on GitHub runners and therefore are not very accurate and can differ a bit since this library measures benchmarks in single digit milliseconds range or even below. They are generally okay to measure large differences if something bad got pushed but are not as reliable as the results of benchmark table below which are always executed on the specified specs.
Benchmark | Mode | Cnt | Score** | Error | Units |
---|---|---|---|---|---|
getByAlias -> :+1: |
avgt | 10 | 59,509 | ยฑ 0,608 | ns/op |
getByAlias -> nope |
avgt | 10 | 72,004 | ยฑ 0,546 | ns/op |
containsEmoji | avgt | 10 | 1,403 | ยฑ 0,004 | ms/op |
extractEmojisInOrder | avgt | 10 | 1,382 | ยฑ 0,013 | ms/op |
extractEmojisInOrderOnlyEmojisLengthDescending | avgt | 10 | 6,013 | ยฑ 0,022 | ms/op |
extractEmojisInOrderOnlyEmojisRandomOrder | avgt | 10 | 6,614 | ยฑ 0,045 | ms/op |
extractEmojisInOrderWithIndex | avgt | 10 | 1,814 | ยฑ 0,002 | ms/op |
removeAllEmojis | avgt | 10 | 2,264 | ยฑ 0,370 | ms/op |
replaceAllEmojis | avgt | 10 | 2,517 | ยฑ 0,020 | ms/op |
replaceAllEmojisFunction | avgt | 10 | 2,502 | ยฑ 0,023 | ms/op |
Click to see the benchmark details
CPU: Intelยฎ Coreโข i7-13700K
VM version: JDK 1.8.0_372, OpenJDK 64-Bit Server VM, 25.372-b07
Blackhole mode: full + dont-inline hint (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
Warmup: 5 iterations, 10 s each
Measurement: 5 iterations, 10 s each
Timeout: 10 min per iteration
Threads: 1 thread, will synchronize iterations
Benchmark mode: Average time, time/op
** Score depends on many factors like text size and emoji count if used as an argument. For this benchmark relatively large files were used. Click Here to see the benchmark code and resources.
๐พ Emoji JSON list Generation
The emoji list can be easily generated with the generate
Gradle task. The generated list will be saved in the
public
folder.
Project setup
To get started with your local development, execute the generate
Gradle task in the group jemoji
.