commit
007a13e566
|
@ -0,0 +1,208 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Board {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Board.class);
|
||||
|
||||
private final int[][] board;
|
||||
|
||||
private final int score;
|
||||
|
||||
public Board(int size) {
|
||||
assert(size > 0);
|
||||
|
||||
this.board = new int[size][];
|
||||
this.score = 0;
|
||||
|
||||
for (int x = 0; x < size; ++x) {
|
||||
this.board[x] = new int[size];
|
||||
for (int y = 0; y < size; ++y) {
|
||||
board[x][y] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Board(int[][] board, int score) {
|
||||
this.score = score;
|
||||
this.board = new int[board.length][];
|
||||
|
||||
for (int x = 0; x < board.length; ++x) {
|
||||
this.board[x] = Arrays.copyOf(board[x], board[x].length);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return board.length;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public int getCell(Cell cell) {
|
||||
int x = cell.getX();
|
||||
int y = cell.getY();
|
||||
assert(x >= 0 && x < board.length);
|
||||
assert(y >= 0 && y < board.length);
|
||||
|
||||
return board[x][y];
|
||||
}
|
||||
|
||||
public boolean isEmpty(Cell cell) {
|
||||
return getCell(cell) == 0;
|
||||
}
|
||||
|
||||
public List<Cell> emptyCells() {
|
||||
List<Cell> result = new ArrayList<>();
|
||||
for (int x = 0; x < board.length; ++x) {
|
||||
for (int y = 0; y < board[x].length; ++y) {
|
||||
Cell cell = new Cell(x, y);
|
||||
if (isEmpty(cell)) {
|
||||
result.add(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Board placeTile(Cell cell, int number) {
|
||||
if (!isEmpty(cell)) {
|
||||
throw new IllegalArgumentException("That cell is not empty");
|
||||
}
|
||||
|
||||
Board result = new Board(this.board, this.score);
|
||||
result.board[cell.getX()][cell.getY()] = number;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Board move(Move move) {
|
||||
// Clone the board
|
||||
int[][] tiles = new int[this.board.length][];
|
||||
for (int x = 0; x < this.board.length; ++x) {
|
||||
tiles[x] = Arrays.copyOf(this.board[x], this.board[x].length);
|
||||
}
|
||||
|
||||
LOG.debug("Before move: {}", Arrays.deepToString(tiles));
|
||||
// If we're doing an Left/Right move then transpose the board to make it a Up/Down move
|
||||
if (move == Move.LEFT || move == Move.RIGHT) {
|
||||
tiles = transpose(tiles);
|
||||
LOG.debug("After transpose: {}", Arrays.deepToString(tiles));
|
||||
}
|
||||
// If we're doing a Right/Down move then reverse the board.
|
||||
// With the above we're now always doing an Up move
|
||||
if (move == Move.DOWN || move == Move.RIGHT) {
|
||||
tiles = reverse(tiles);
|
||||
LOG.debug("After reverse: {}", Arrays.deepToString(tiles));
|
||||
}
|
||||
LOG.debug("Ready to move: {}", Arrays.deepToString(tiles));
|
||||
|
||||
// Shift everything up
|
||||
int[][] result = new int[tiles.length][];
|
||||
int newScore = 0;
|
||||
for (int x = 0; x < tiles.length; ++x) {
|
||||
LinkedList<Integer> thisRow = new LinkedList<>();
|
||||
for (int y = 0; y < tiles[0].length; ++y) {
|
||||
if (tiles[x][y] > 0) {
|
||||
thisRow.add(tiles[x][y]);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug("Unmerged row: {}", thisRow);
|
||||
LinkedList<Integer> newRow = new LinkedList<>();
|
||||
while (thisRow.size() >= 2) {
|
||||
int first = thisRow.pop();
|
||||
int second = thisRow.peek();
|
||||
LOG.debug("Looking at numbers {} and {}", first, second);
|
||||
if (second == first) {
|
||||
LOG.debug("Numbers match, combining");
|
||||
int newNumber = first * 2;
|
||||
newRow.add(newNumber);
|
||||
newScore += newNumber;
|
||||
thisRow.pop();
|
||||
} else {
|
||||
LOG.debug("Numbers don't match");
|
||||
newRow.add(first);
|
||||
}
|
||||
}
|
||||
newRow.addAll(thisRow);
|
||||
LOG.debug("Merged row: {}", newRow);
|
||||
|
||||
result[x] = new int[tiles[0].length];
|
||||
for (int y = 0; y < tiles[0].length; ++y) {
|
||||
if (newRow.isEmpty()) {
|
||||
result[x][y] = 0;
|
||||
} else {
|
||||
result[x][y] = newRow.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.debug("After moves: {}", Arrays.deepToString(result));
|
||||
|
||||
// Un-reverse the board
|
||||
if (move == Move.DOWN || move == Move.RIGHT) {
|
||||
result = reverse(result);
|
||||
LOG.debug("After reverse: {}", Arrays.deepToString(result));
|
||||
}
|
||||
// Un-transpose the board
|
||||
if (move == Move.LEFT || move == Move.RIGHT) {
|
||||
result = transpose(result);
|
||||
LOG.debug("After transpose: {}", Arrays.deepToString(result));
|
||||
}
|
||||
return new Board(result, this.score + newScore);
|
||||
}
|
||||
|
||||
private static int[][] transpose(int[][] input) {
|
||||
int[][] result = new int[input.length][];
|
||||
|
||||
for (int x = 0; x < input.length; ++x) {
|
||||
result[x] = new int[input[0].length];
|
||||
for (int y = 0; y < input[0].length; ++y) {
|
||||
result[x][y] = input[y][x];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int[][] reverse(int[][] input) {
|
||||
int[][] result = new int[input.length][];
|
||||
|
||||
for (int x = 0; x < input.length; ++x) {
|
||||
result[x] = new int[input[0].length];
|
||||
for (int y = 0; y < input[0].length; ++y) {
|
||||
result[x][y] = input[x][input.length - y - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Arrays.deepToString(board);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Board board1 = (Board) o;
|
||||
return Arrays.deepEquals(board, board1.board);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.deepHashCode(board);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class Cell {
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public Cell(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", Cell.class.getSimpleName() + "[", "]").add("x=" + x).add("y=" + y).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Computer {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Computer.class);
|
||||
|
||||
private final SecureRandom rng = new SecureRandom();
|
||||
|
||||
public Board makeMove(Board input) {
|
||||
List<Cell> emptyCells = input.emptyCells();
|
||||
LOG.info("Number of empty cells: {}", emptyCells.size());
|
||||
|
||||
double numberToPlace = rng.nextDouble();
|
||||
LOG.info("New number probability: {}", numberToPlace);
|
||||
|
||||
int indexToPlace = rng.nextInt(emptyCells.size());
|
||||
Cell cellToPlace = emptyCells.get(indexToPlace);
|
||||
LOG.info("Placing number into empty cell: {}", cellToPlace);
|
||||
|
||||
return input.placeTile(cellToPlace, numberToPlace >= 0.9 ? 4 : 2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.math3.util.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Human {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Human.class);
|
||||
|
||||
public Board makeMove(Board input) {
|
||||
// For each move in MOVE
|
||||
// Generate board from move
|
||||
// Generate Score for Board
|
||||
// Return board with the best score
|
||||
//
|
||||
// Generate Score
|
||||
// If Depth Limit
|
||||
// Return Final Score
|
||||
// Total Score = 0
|
||||
// For every empty square in new board
|
||||
// Generate board with "2" in square
|
||||
// Calculate Score
|
||||
// Total Score += (Score * 0.9)
|
||||
// Generate board with "4" in square
|
||||
// Calculate Score
|
||||
// Total Score += (Score * 0.1)
|
||||
//
|
||||
// Calculate Score
|
||||
// For each move in MOVE
|
||||
// Generate board from move
|
||||
// Generate score for board
|
||||
// Return the best generated score
|
||||
|
||||
return Arrays.stream(Move.values())
|
||||
.parallel()
|
||||
.map(input::move)
|
||||
.filter(board -> !board.equals(input))
|
||||
.max(Comparator.comparingInt(board -> generateScore(board, 0)))
|
||||
.orElse(input);
|
||||
}
|
||||
|
||||
private int generateScore(Board board, int depth) {
|
||||
if (depth >= 3) {
|
||||
int finalScore = calculateFinalScore(board);
|
||||
LOG.debug("Final score for board {}: {}", board,finalScore);
|
||||
return finalScore;
|
||||
}
|
||||
|
||||
return board.emptyCells().stream()
|
||||
.parallel()
|
||||
.flatMap(cell -> Stream.of(new Pair<>(cell, 2), new Pair<>(cell, 4)))
|
||||
.mapToInt(move -> {
|
||||
LOG.debug("Simulating move {} at depth {}", move, depth);
|
||||
Board newBoard = board.placeTile(move.getFirst(), move.getSecond());
|
||||
int boardScore = calculateScore(newBoard, depth + 1);
|
||||
int calculatedScore = (int) (boardScore * (move.getSecond() == 2 ? 0.9 : 0.1));
|
||||
LOG.debug("Calculated score for board {} and move {} at depth {}: {}", newBoard, move, depth, calculatedScore);
|
||||
return calculatedScore;
|
||||
})
|
||||
.sum();
|
||||
}
|
||||
|
||||
private int calculateScore(Board board, int depth) {
|
||||
return Arrays.stream(Move.values())
|
||||
.parallel()
|
||||
.map(board::move)
|
||||
.filter(moved -> !moved.equals(board))
|
||||
.mapToInt(newBoard -> generateScore(newBoard, depth))
|
||||
.max()
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
private int calculateFinalScore(Board board) {
|
||||
List<List<Integer>> rowsToScore = new ArrayList<>();
|
||||
for (int i = 0; i < board.getSize(); ++i) {
|
||||
List<Integer> row = new ArrayList<>();
|
||||
List<Integer> col = new ArrayList<>();
|
||||
|
||||
for (int j = 0; j < board.getSize(); ++j) {
|
||||
row.add(board.getCell(new Cell(i, j)));
|
||||
col.add(board.getCell(new Cell(j, i)));
|
||||
}
|
||||
|
||||
rowsToScore.add(row);
|
||||
rowsToScore.add(col);
|
||||
}
|
||||
|
||||
return rowsToScore.stream()
|
||||
.parallel()
|
||||
.mapToInt(row -> {
|
||||
List<Integer> preMerged = row.stream()
|
||||
.filter(value -> value != 0)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int numMerges = 0;
|
||||
int monotonicityLeft = 0;
|
||||
int monotonicityRight = 0;
|
||||
for (int i = 0; i < preMerged.size() - 1; ++i) {
|
||||
Integer first = preMerged.get(i);
|
||||
Integer second = preMerged.get(i + 1);
|
||||
if (first.equals(second)) {
|
||||
++numMerges;
|
||||
} else if (first > second) {
|
||||
monotonicityLeft += first - second;
|
||||
} else {
|
||||
monotonicityRight += second - first;
|
||||
}
|
||||
}
|
||||
|
||||
int score = 1000;
|
||||
score += 250 * row.stream().filter(value -> value == 0).count();
|
||||
score += 750 * numMerges;
|
||||
score -= 10 * row.stream().mapToInt(value -> value).sum();
|
||||
score -= 50 * Math.min(monotonicityLeft, monotonicityRight);
|
||||
return score;
|
||||
})
|
||||
.sum();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
public enum Move {
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.baeldung.algorithms.play2048;
|
||||
|
||||
public class Play2048 {
|
||||
private static final int SIZE = 3;
|
||||
private static final int INITIAL_NUMBERS = 2;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// The board and players
|
||||
Board board = new Board(SIZE);
|
||||
Computer computer = new Computer();
|
||||
Human human = new Human();
|
||||
|
||||
// The computer has two moves first
|
||||
System.out.println("Setup");
|
||||
System.out.println("=====");
|
||||
for (int i = 0; i < INITIAL_NUMBERS; ++i) {
|
||||
board = computer.makeMove(board);
|
||||
}
|
||||
|
||||
printBoard(board);
|
||||
do {
|
||||
board = human.makeMove(board);
|
||||
System.out.println("Human move");
|
||||
System.out.println("==========");
|
||||
printBoard(board);
|
||||
|
||||
board = computer.makeMove(board);
|
||||
System.out.println("Computer move");
|
||||
System.out.println("=============");
|
||||
printBoard(board);
|
||||
} while (!board.emptyCells().isEmpty());
|
||||
|
||||
System.out.println("Final Score: " + board.getScore());
|
||||
|
||||
}
|
||||
|
||||
private static void printBoard(Board board) {
|
||||
StringBuilder topLines = new StringBuilder();
|
||||
StringBuilder midLines = new StringBuilder();
|
||||
for (int x = 0; x < board.getSize(); ++x) {
|
||||
topLines.append("+--------");
|
||||
midLines.append("| ");
|
||||
}
|
||||
topLines.append("+");
|
||||
midLines.append("|");
|
||||
|
||||
|
||||
for (int y = 0; y < board.getSize(); ++y) {
|
||||
System.out.println(topLines);
|
||||
System.out.println(midLines);
|
||||
for (int x = 0; x < board.getSize(); ++x) {
|
||||
Cell cell = new Cell(x, y);
|
||||
System.out.print("|");
|
||||
if (board.isEmpty(cell)) {
|
||||
System.out.print(" ");
|
||||
} else {
|
||||
StringBuilder output = new StringBuilder(Integer.toString(board.getCell(cell)));
|
||||
while (output.length() < 8) {
|
||||
output.append(" ");
|
||||
if (output.length() < 8) {
|
||||
output.insert(0, " ");
|
||||
}
|
||||
}
|
||||
System.out.print(output);
|
||||
}
|
||||
}
|
||||
System.out.println("|");
|
||||
System.out.println(midLines);
|
||||
}
|
||||
System.out.println(topLines);
|
||||
System.out.println("Score: " + board.getScore());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.determinedatatype
|
||||
|
||||
class Person {
|
||||
|
||||
private int ageAsInt
|
||||
private Double ageAsDouble
|
||||
private String ageAsString
|
||||
|
||||
Person() {}
|
||||
Person(int ageAsInt) { this.ageAsInt = ageAsInt}
|
||||
Person(Double ageAsDouble) { this.ageAsDouble = ageAsDouble}
|
||||
Person(String ageAsString) { this.ageAsString = ageAsString}
|
||||
}
|
||||
class Student extends Person {}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.determinedatatype
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import com.baeldung.determinedatatype.Person
|
||||
|
||||
public class PersonTest {
|
||||
|
||||
@Test
|
||||
public void givenWhenParameterTypeIsInteger_thenReturnTrue() {
|
||||
Person personObj = new Person(10)
|
||||
Assert.assertTrue(personObj.ageAsInt instanceof Integer)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWhenParameterTypeIsDouble_thenReturnTrue() {
|
||||
Person personObj = new Person(10.0)
|
||||
Assert.assertTrue((personObj.ageAsDouble).getClass() == Double)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWhenParameterTypeIsString_thenReturnTrue() {
|
||||
Person personObj = new Person("10 years")
|
||||
Assert.assertTrue(personObj.ageAsString.class == String)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenClassName_WhenParameterIsInteger_thenReturnTrue() {
|
||||
Assert.assertTrue(Person.class.getDeclaredField('ageAsInt').type == int.class)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWhenObjectIsInstanceOfType_thenReturnTrue() {
|
||||
Person personObj = new Person()
|
||||
Assert.assertTrue(personObj instanceof Person)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWhenInstanceIsOfSubtype_thenReturnTrue() {
|
||||
Student studentObj = new Student()
|
||||
Assert.assertTrue(studentObj in Person)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGroovyList_WhenFindClassName_thenReturnTrue() {
|
||||
def ageList = ['ageAsString','ageAsDouble', 10]
|
||||
Assert.assertTrue(ageList.class == ArrayList)
|
||||
Assert.assertTrue(ageList.getClass() == ArrayList)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGrooyMap_WhenFindClassName_thenReturnTrue() {
|
||||
def ageMap = [ageAsString: '10 years', ageAsDouble: 10.0]
|
||||
Assert.assertFalse(ageMap.class == LinkedHashMap)
|
||||
}
|
||||
}
|
|
@ -4,19 +4,19 @@ import java.util.Objects;
|
|||
|
||||
public record Person (String name, String address) {
|
||||
|
||||
public static String UNKWOWN_ADDRESS = "Unknown";
|
||||
public static String UNNAMED = "Unnamed";
|
||||
public static String UNKNOWN_ADDRESS = "Unknown";
|
||||
public static String UNNAMED = "Unnamed";
|
||||
|
||||
public Person {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(address);
|
||||
}
|
||||
public Person {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(address);
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this(name, UNKWOWN_ADDRESS);
|
||||
}
|
||||
public Person(String name) {
|
||||
this(name, UNKNOWN_ADDRESS);
|
||||
}
|
||||
|
||||
public static Person unnamed(String address) {
|
||||
return new Person(UNNAMED, address);
|
||||
}
|
||||
}
|
||||
public static Person unnamed(String address) {
|
||||
return new Person(UNNAMED, address);
|
||||
}
|
||||
}
|
|
@ -134,7 +134,7 @@ public class PersonTest {
|
|||
Person person = new Person(name);
|
||||
|
||||
assertEquals(name, person.name());
|
||||
assertEquals(Person.UNKWOWN_ADDRESS, person.address());
|
||||
assertEquals(Person.UNKNOWN_ADDRESS, person.address());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -147,4 +147,4 @@ public class PersonTest {
|
|||
assertEquals(Person.UNNAMED, person.name());
|
||||
assertEquals(address, person.address());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-8-datetime</artifactId>
|
||||
<artifactId>core-java-8-datetime-2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<name>core-java-8-datetime</name>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -41,7 +41,6 @@
|
|||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-datetime-java8</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class JavaArraysToStringUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
assertTrue(arrayOfObjects.toString().startsWith("[Ljava.lang.Object;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfArray_whenUsingArraysToStringToConvert_thenValueOfObjectsAreShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfDeepArray_whenUsingArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() {
|
||||
Object[] innerArray = { "We", "Are", "Inside" };
|
||||
Object[] arrayOfObjects = { "John", 2, innerArray };
|
||||
assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfDeepArray_whenUsingStreamsToConvert_thenValueOfObjectsAreShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
List<String> listOfString = Stream.of(arrayOfObjects)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(listOfString.toString(), "[John, 2, true]");
|
||||
}
|
||||
}
|
|
@ -9,3 +9,4 @@
|
|||
- [Differences Between Collection.clear() and Collection.removeAll()](https://www.baeldung.com/java-collection-clear-vs-removeall)
|
||||
- [Performance of contains() in a HashSet vs ArrayList](https://www.baeldung.com/java-hashset-arraylist-contains-performance)
|
||||
- [Fail-Safe Iterator vs Fail-Fast Iterator](https://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator)
|
||||
- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package com.baeldung.abaproblem;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Account {
|
||||
|
||||
private AtomicInteger balance;
|
||||
private AtomicInteger transactionCount;
|
||||
private ThreadLocal<Integer> currentThreadCASFailureCount;
|
||||
|
||||
public Account() {
|
||||
this.balance = new AtomicInteger(0);
|
||||
this.transactionCount = new AtomicInteger(0);
|
||||
this.currentThreadCASFailureCount = new ThreadLocal<>();
|
||||
this.currentThreadCASFailureCount.set(0);
|
||||
}
|
||||
|
||||
public int getBalance() {
|
||||
return balance.get();
|
||||
}
|
||||
|
||||
public int getTransactionCount() {
|
||||
return transactionCount.get();
|
||||
}
|
||||
|
||||
public int getCurrentThreadCASFailureCount() {
|
||||
return currentThreadCASFailureCount.get();
|
||||
}
|
||||
|
||||
public boolean withdraw(int amount) {
|
||||
int current = getBalance();
|
||||
maybeWait();
|
||||
boolean result = balance.compareAndSet(current, current - amount);
|
||||
if (result) {
|
||||
transactionCount.incrementAndGet();
|
||||
} else {
|
||||
int currentCASFailureCount = currentThreadCASFailureCount.get();
|
||||
currentThreadCASFailureCount.set(currentCASFailureCount + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void maybeWait() {
|
||||
if ("thread1".equals(Thread.currentThread().getName())) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deposit(int amount) {
|
||||
int current = balance.get();
|
||||
boolean result = balance.compareAndSet(current, current + amount);
|
||||
if (result) {
|
||||
transactionCount.incrementAndGet();
|
||||
} else {
|
||||
int currentCASFailureCount = currentThreadCASFailureCount.get();
|
||||
currentThreadCASFailureCount.set(currentCASFailureCount + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.baeldung.abaproblem;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class AccountUnitTest {
|
||||
|
||||
private Account account;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
account = new Account();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zeroBalanceInitializationTest() {
|
||||
assertEquals(0, account.getBalance());
|
||||
assertEquals(0, account.getTransactionCount());
|
||||
assertEquals(0, account.getCurrentThreadCASFailureCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void depositTest() {
|
||||
final int moneyToDeposit = 50;
|
||||
|
||||
assertTrue(account.deposit(moneyToDeposit));
|
||||
|
||||
assertEquals(moneyToDeposit, account.getBalance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withdrawTest() throws InterruptedException {
|
||||
final int defaultBalance = 50;
|
||||
final int moneyToWithdraw = 20;
|
||||
|
||||
account.deposit(defaultBalance);
|
||||
|
||||
assertTrue(account.withdraw(moneyToWithdraw));
|
||||
|
||||
assertEquals(defaultBalance - moneyToWithdraw, account.getBalance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void abaProblemTest() throws InterruptedException {
|
||||
final int defaultBalance = 50;
|
||||
|
||||
final int amountToWithdrawByThread1 = 20;
|
||||
final int amountToWithdrawByThread2 = 10;
|
||||
final int amountToDepositByThread2 = 10;
|
||||
|
||||
assertEquals(0, account.getTransactionCount());
|
||||
assertEquals(0, account.getCurrentThreadCASFailureCount());
|
||||
account.deposit(defaultBalance);
|
||||
assertEquals(1, account.getTransactionCount());
|
||||
|
||||
Thread thread1 = new Thread(() -> {
|
||||
|
||||
// this will take longer due to the name of the thread
|
||||
assertTrue(account.withdraw(amountToWithdrawByThread1));
|
||||
|
||||
// thread 1 fails to capture ABA problem
|
||||
assertNotEquals(1, account.getCurrentThreadCASFailureCount());
|
||||
|
||||
}, "thread1");
|
||||
|
||||
Thread thread2 = new Thread(() -> {
|
||||
|
||||
assertTrue(account.deposit(amountToDepositByThread2));
|
||||
assertEquals(defaultBalance + amountToDepositByThread2, account.getBalance());
|
||||
|
||||
// this will be fast due to the name of the thread
|
||||
assertTrue(account.withdraw(amountToWithdrawByThread2));
|
||||
|
||||
// thread 1 didn't finish yet, so the original value will be in place for it
|
||||
assertEquals(defaultBalance, account.getBalance());
|
||||
|
||||
assertEquals(0, account.getCurrentThreadCASFailureCount());
|
||||
}, "thread2");
|
||||
|
||||
thread1.start();
|
||||
thread2.start();
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
|
||||
// compareAndSet operation succeeds for thread 1
|
||||
assertEquals(defaultBalance - amountToWithdrawByThread1, account.getBalance());
|
||||
|
||||
//but there are other transactions
|
||||
assertNotEquals(2, account.getTransactionCount());
|
||||
|
||||
// thread 2 did two modifications as well
|
||||
assertEquals(4, account.getTransactionCount());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#Core Java Console
|
||||
|
||||
[Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output)
|
||||
[Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf)
|
||||
[ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java)
|
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-console</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-console</name>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-console</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>${exec-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<mainClass>com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed</mainClass>
|
||||
<arguments>
|
||||
<argument>-Xmx300m</argument>
|
||||
<argument>-XX:+UseParallelGC</argument>
|
||||
<argument>-classpath</argument>
|
||||
<classpath />
|
||||
<argument>com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${source.version}</source>
|
||||
<target>${target.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>integration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*ManualTest.java</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
<include>**/*IntTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.mime>json</test.mime>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>${exec-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-benchmarks</id>
|
||||
<!-- <phase>integration-test</phase> -->
|
||||
<phase>none</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<classpathScope>test</classpathScope>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-classpath</argument>
|
||||
<classpath />
|
||||
<argument>org.openjdk.jmh.Main</argument>
|
||||
<argument>.*</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
|
||||
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
|
||||
<source.version>1.8</source.version>
|
||||
<target.version>1.8</target.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -1,10 +1,9 @@
|
|||
package com.baeldung.asciiart;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import com.baeldung.asciiart.AsciiArt.Settings;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.asciiart.AsciiArt.Settings;
|
||||
import java.awt.*;
|
||||
|
||||
public class AsciiArtIntegrationTest {
|
||||
|
||||
|
@ -16,5 +15,4 @@ public class AsciiArtIntegrationTest {
|
|||
|
||||
asciiArt.drawString(text, "*", settings);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,4 +8,5 @@ This module contains articles about date operations in Java.
|
|||
- [Converting Java Date to OffsetDateTime](https://www.baeldung.com/java-convert-date-to-offsetdatetime)
|
||||
- [How to Set the JVM Time Zone](https://www.baeldung.com/java-jvm-time-zone)
|
||||
- [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week)
|
||||
- [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-date-operations-1)
|
||||
|
|
|
@ -12,3 +12,4 @@ This module contains articles about working with the Java Virtual Machine (JVM).
|
|||
- [Guide to System.gc()](https://www.baeldung.com/java-system-gc)
|
||||
- [Runtime.getRuntime().halt() vs System.exit() in Java](https://www.baeldung.com/java-runtime-halt-vs-system-exit)
|
||||
- [Adding Shutdown Hooks for JVM Applications](https://www.baeldung.com/jvm-shutdown-hooks)
|
||||
- [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object)
|
||||
|
|
|
@ -7,3 +7,6 @@ This module contains articles about types in Java
|
|||
- [Guide to the this Java Keyword](https://www.baeldung.com/java-this)
|
||||
- [Nested Classes in Java](https://www.baeldung.com/java-nested-classes)
|
||||
- [Marker Interfaces in Java](https://www.baeldung.com/java-marker-interfaces)
|
||||
- [Iterating Over Enum Values in Java](https://www.baeldung.com/java-enum-iteration)
|
||||
- [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values)
|
||||
- [A Guide to Java Enums](https://www.baeldung.com/a-guide-to-java-enums)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package com.baeldung.varargs;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HeapPollutionUnitTest {
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenGenericVararg_whenUsedUnsafe_shouldThrowClassCastException() {
|
||||
String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList());
|
||||
|
||||
assertEquals("one", one);
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenGenericVararg_whenRefEscapes_mayCauseSubtleBugs() {
|
||||
String[] args = returnAsIs("One", "Two");
|
||||
}
|
||||
|
||||
private static String firstOfFirst(List<String>... strings) {
|
||||
List<Integer> ints = Collections.singletonList(42);
|
||||
Object[] objects = strings;
|
||||
objects[0] = ints;
|
||||
|
||||
return strings[0].get(0);
|
||||
}
|
||||
|
||||
private static <T> T[] toArray(T... arguments) {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private static <T> T[] returnAsIs(T a, T b) {
|
||||
return toArray(a, b);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ This module contains articles about core features in the Java language
|
|||
|
||||
### Relevant Articles:
|
||||
- [Generate equals() and hashCode() with Eclipse](https://www.baeldung.com/java-eclipse-equals-and-hashcode)
|
||||
- [Iterating Over Enum Values in Java](https://www.baeldung.com/java-enum-iteration)
|
||||
- [Comparator and Comparable in Java](https://www.baeldung.com/java-comparator-comparable)
|
||||
- [Recursion In Java](https://www.baeldung.com/java-recursion)
|
||||
- [A Guide to the finalize Method in Java](https://www.baeldung.com/java-finalize)
|
||||
|
@ -12,8 +11,6 @@ This module contains articles about core features in the Java language
|
|||
- [Using Java Assertions](https://www.baeldung.com/java-assert)
|
||||
- [Synthetic Constructs in Java](https://www.baeldung.com/java-synthetic)
|
||||
- [Retrieving a Class Name in Java](https://www.baeldung.com/java-class-name)
|
||||
- [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values)
|
||||
- [The Java continue and break Keywords](https://www.baeldung.com/java-continue-and-break)
|
||||
- [A Guide to Java Enums](https://www.baeldung.com/a-guide-to-java-enums)
|
||||
- [Infinite Loops in Java](https://www.baeldung.com/infinite-loops-java)
|
||||
- [[More --> ]](/core-java-modules/core-java-lang-2)
|
||||
|
|
|
@ -8,3 +8,5 @@
|
|||
- [Changing Annotation Parameters At Runtime](http://www.baeldung.com/java-reflection-change-annotation-params)
|
||||
- [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies)
|
||||
- [What Causes java.lang.reflect.InvocationTargetException?](https://www.baeldung.com/java-lang-reflect-invocationtargetexception)
|
||||
- [How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null)
|
||||
- [How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method)
|
||||
|
|
|
@ -200,7 +200,7 @@ public class ReflectionUnitTest {
|
|||
@Test
|
||||
public void givenClassField_whenSetsAndGetsValue_thenCorrect() throws Exception {
|
||||
final Class<?> birdClass = Class.forName("com.baeldung.java.reflection.Bird");
|
||||
final Bird bird = (Bird) birdClass.newInstance();
|
||||
final Bird bird = (Bird) birdClass.getConstructor().newInstance();
|
||||
final Field field = birdClass.getDeclaredField("walks");
|
||||
field.setAccessible(true);
|
||||
|
||||
|
@ -266,7 +266,7 @@ public class ReflectionUnitTest {
|
|||
@Test
|
||||
public void givenMethod_whenInvokes_thenCorrect() throws Exception {
|
||||
final Class<?> birdClass = Class.forName("com.baeldung.java.reflection.Bird");
|
||||
final Bird bird = (Bird) birdClass.newInstance();
|
||||
final Bird bird = (Bird) birdClass.getConstructor().newInstance();
|
||||
final Method setWalksMethod = birdClass.getDeclaredMethod("setWalks", boolean.class);
|
||||
final Method walksMethod = birdClass.getDeclaredMethod("walks");
|
||||
final boolean walks = (boolean) walksMethod.invoke(bird);
|
||||
|
|
|
@ -26,6 +26,17 @@ public class StringToIntOrIntegerUnitTest {
|
|||
assertThat(result).isEqualTo(new Integer(42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenCallingValueOf_shouldCacheSomeValues() {
|
||||
for (int i = -128; i <= 127; i++) {
|
||||
String value = i + "";
|
||||
Integer first = Integer.valueOf(value);
|
||||
Integer second = Integer.valueOf(value);
|
||||
|
||||
assertThat(first).isSameAs(second);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenCallingIntegerConstructor_shouldConvertToInt() {
|
||||
String givenString = "42";
|
||||
|
|
|
@ -12,4 +12,6 @@ This module contains articles about string operations.
|
|||
- [L-Trim and R-Trim Alternatives in Java](https://www.baeldung.com/java-trim-alternatives)
|
||||
- [Java Convert PDF to Base64](https://www.baeldung.com/java-convert-pdf-to-base64)
|
||||
- [Encode a String to UTF-8 in Java](https://www.baeldung.com/java-string-encode-utf-8)
|
||||
- [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding)
|
||||
- [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) #remove additional readme file
|
||||
- More articles: [[<-- prev]](../core-java-string-operations)
|
||||
|
|
Binary file not shown.
|
@ -6,3 +6,4 @@ This module contains articles about the measurement of time in Java.
|
|||
- [Guide to the Java Clock Class](http://www.baeldung.com/java-clock)
|
||||
- [Measure Elapsed Time in Java](http://www.baeldung.com/java-measure-elapsed-time)
|
||||
- [Overriding System Time for Testing in Java](https://www.baeldung.com/java-override-system-time)
|
||||
- [Java Timer](http://www.baeldung.com/java-timer-and-timertask)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.java.clock;
|
||||
package com.baeldung.clock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
|
@ -1,35 +1,13 @@
|
|||
## Core Java Cookbooks and Examples
|
||||
|
||||
### Relevant Articles:
|
||||
- [Java Timer](http://www.baeldung.com/java-timer-and-timertask)
|
||||
- [Getting Started with Java Properties](http://www.baeldung.com/java-properties)
|
||||
- [Introduction to Nashorn](http://www.baeldung.com/java-nashorn)
|
||||
- [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency)
|
||||
- [JVM Log Forging](http://www.baeldung.com/jvm-log-forging)
|
||||
- [How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null)
|
||||
- [How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method)
|
||||
- [Introduction to Java Serialization](http://www.baeldung.com/java-serialization)
|
||||
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
||||
- [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin)
|
||||
- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack)
|
||||
- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac)
|
||||
- [Introduction to Javadoc](http://www.baeldung.com/javadoc)
|
||||
- [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable)
|
||||
- [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java)
|
||||
- [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid)
|
||||
- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
|
||||
- [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler)
|
||||
- [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object)
|
||||
- [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions)
|
||||
- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties)
|
||||
- [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources)
|
||||
- [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding)
|
||||
- [Graphs in Java](https://www.baeldung.com/java-graphs)
|
||||
- [Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output)
|
||||
- [Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf)
|
||||
- [Retrieve Fields from a Java Class Using Reflection](https://www.baeldung.com/java-reflection-class-fields)
|
||||
- [Using Curl in Java](https://www.baeldung.com/java-curl)
|
||||
- [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year)
|
||||
- [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post)
|
||||
- [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause)
|
||||
- [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii)
|
||||
[Getting Started with Java Properties](http://www.baeldung.com/java-properties)
|
||||
[Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency)
|
||||
[Introduction to Java Serialization](http://www.baeldung.com/java-serialization)
|
||||
[Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
||||
[Compiling Java *.class Files with javac](http://www.baeldung.com/javac)
|
||||
[Introduction to Javadoc](http://www.baeldung.com/javadoc)
|
||||
[Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable)
|
||||
[What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid)
|
||||
[A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
|
||||
[Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties)
|
||||
|
|
|
@ -3,30 +3,57 @@ package com.baeldung.uuid;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDGenerator {
|
||||
|
||||
/**
|
||||
* These are predefined UUID for name spaces
|
||||
*/
|
||||
private static final String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
|
||||
private static final String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
|
||||
private static final String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
|
||||
private static final String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
|
||||
|
||||
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
System.out.println("Type 3 : " + generateType3UUID(NAMESPACE_DNS, "google.com"));
|
||||
System.out.println("Type 4 : " + generateType4UUID());
|
||||
System.out.println("Type 5 : " + generateType5UUID(NAMESPACE_URL, "google.com"));
|
||||
System.out.println("Unique key : " + generateUniqueKeysWithUUIDAndMessageDigest());
|
||||
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/**
|
||||
* Type 1 UUID Generation
|
||||
*/
|
||||
public static UUID generateType1UUID() {
|
||||
|
||||
long most64SigBits = get64MostSignificantBitsForVersion1();
|
||||
long least64SigBits = get64LeastSignificantBitsForVersion1();
|
||||
|
||||
return new UUID(most64SigBits, least64SigBits);
|
||||
}
|
||||
|
||||
private static long get64LeastSignificantBitsForVersion1() {
|
||||
Random random = new Random();
|
||||
long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL;
|
||||
long variant3BitFlag = 0x8000000000000000L;
|
||||
return random63BitLong + variant3BitFlag;
|
||||
}
|
||||
|
||||
private static long get64MostSignificantBitsForVersion1() {
|
||||
LocalDateTime start = LocalDateTime.of(1582, 10, 15, 0, 0, 0);
|
||||
Duration duration = Duration.between(start, LocalDateTime.now());
|
||||
long seconds = duration.getSeconds();
|
||||
long nanos = duration.getNano();
|
||||
long timeForUuidIn100Nanos = seconds * 10000000 + nanos * 100;
|
||||
long least12SignificatBitOfTime = (timeForUuidIn100Nanos & 0x000000000000FFFFL) >> 4;
|
||||
long version = 1 << 12;
|
||||
return (timeForUuidIn100Nanos & 0xFFFFFFFFFFFF0000L) + version + least12SignificatBitOfTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type 3 UUID Generation
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static UUID generateType3UUID(String namespace, String name) throws UnsupportedEncodingException {
|
||||
|
||||
byte[] nameSpaceBytes = bytesFromUUID(namespace);
|
||||
byte[] nameBytes = name.getBytes("UTF-8");
|
||||
byte[] result = joinBytes(nameSpaceBytes, nameBytes);
|
||||
|
||||
return UUID.nameUUIDFromBytes(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,28 +64,18 @@ public class UUIDGenerator {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type 3 UUID Generation
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static UUID generateType3UUID(String namespace, String name) throws UnsupportedEncodingException {
|
||||
String source = namespace + name;
|
||||
byte[] bytes = source.getBytes("UTF-8");
|
||||
UUID uuid = UUID.nameUUIDFromBytes(bytes);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type 5 UUID Generation
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static UUID generateType5UUID(String namespace, String name) throws UnsupportedEncodingException {
|
||||
String source = namespace + name;
|
||||
byte[] bytes = source.getBytes("UTF-8");
|
||||
UUID uuid = type5UUIDFromBytes(bytes);
|
||||
return uuid;
|
||||
|
||||
byte[] nameSpaceBytes = bytesFromUUID(namespace);
|
||||
byte[] nameBytes = name.getBytes("UTF-8");
|
||||
byte[] result = joinBytes(nameSpaceBytes, nameBytes);
|
||||
|
||||
return type5UUIDFromBytes(result);
|
||||
}
|
||||
|
||||
public static UUID type5UUIDFromBytes(byte[] name) {
|
||||
|
@ -91,20 +108,20 @@ public class UUIDGenerator {
|
|||
|
||||
/**
|
||||
* Unique Keys Generation Using Message Digest and Type 4 UUID
|
||||
*
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
*
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static String generateUniqueKeysWithUUIDAndMessageDigest() throws NoSuchAlgorithmException, UnsupportedEncodingException {
|
||||
MessageDigest salt = MessageDigest.getInstance("SHA-256");
|
||||
salt.update(UUID.randomUUID()
|
||||
.toString()
|
||||
.getBytes("UTF-8"));
|
||||
.toString()
|
||||
.getBytes("UTF-8"));
|
||||
String digest = bytesToHex(salt.digest());
|
||||
return digest;
|
||||
}
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
|
@ -114,4 +131,37 @@ public class UUIDGenerator {
|
|||
return new String(hexChars);
|
||||
}
|
||||
|
||||
}
|
||||
private static byte[] bytesFromUUID(String uuidHexString) {
|
||||
String normalizedUUIDHexString = uuidHexString.replace("-","");
|
||||
|
||||
assert normalizedUUIDHexString.length() == 32;
|
||||
|
||||
byte[] bytes = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
byte b = hexToByte(normalizedUUIDHexString.substring(i*2, i*2+2));
|
||||
bytes[i] = b;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte hexToByte(String hexString) {
|
||||
int firstDigit = Character.digit(hexString.charAt(0),16);
|
||||
int secondDigit = Character.digit(hexString.charAt(1),16);
|
||||
return (byte) ((firstDigit << 4) + secondDigit);
|
||||
}
|
||||
|
||||
public static byte[] joinBytes(byte[] byteArray1, byte[] byteArray2) {
|
||||
int finalLength = byteArray1.length + byteArray2.length;
|
||||
byte[] result = new byte[finalLength];
|
||||
|
||||
for(int i = 0; i < byteArray1.length; i++) {
|
||||
result[i] = byteArray1[i];
|
||||
}
|
||||
|
||||
for(int i = 0; i < byteArray2.length; i++) {
|
||||
result[byteArray1.length+i] = byteArray2[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.baeldung.uuid;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class UUIDGeneratorUnitTest {
|
||||
|
||||
private static final String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
|
||||
private static final String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
|
||||
|
||||
@Test
|
||||
public void version_1_UUID_is_generated_with_correct_length_version_and_variant() {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType1UUID();
|
||||
|
||||
assertEquals(36, uuid.toString().length());
|
||||
assertEquals(1, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void version_3_UUID_is_correctly_generated_for_domain_baeldung_com() throws UnsupportedEncodingException {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType3UUID(NAMESPACE_DNS, "baeldung.com");
|
||||
|
||||
assertEquals("23785b78-0132-3ac6-aff6-cfd5be162139", uuid.toString());
|
||||
assertEquals(3, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void version_3_UUID_is_correctly_generated_for_domain_d() throws UnsupportedEncodingException {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType3UUID(NAMESPACE_DNS, "d");
|
||||
|
||||
assertEquals("dbd41ecb-f466-33de-b309-1468addfc63b", uuid.toString());
|
||||
assertEquals(3, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void version_4_UUID_is_generated_with_correct_length_version_and_variant() {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType4UUID();
|
||||
|
||||
assertEquals(36, uuid.toString().length());
|
||||
assertEquals(4, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void version_5_UUID_is_correctly_generated_for_domain_baeldung_com() throws UnsupportedEncodingException {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType5UUID(NAMESPACE_URL, "baeldung.com");
|
||||
|
||||
assertEquals("aeff44a5-8a61-52b6-bcbe-c8e5bd7d0300", uuid.toString());
|
||||
assertEquals(5, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
## Core Kotlin 2
|
||||
|
||||
This module contains articles about Kotlin core features.
|
||||
|
||||
### Relevant articles:
|
||||
- [Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates)
|
||||
- [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator)
|
||||
- [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences)
|
||||
- [[<-- Prev]](/core-kotlin-modules/core-kotlin)
|
|
@ -10,3 +10,4 @@ This module contains articles about core Kotlin collections.
|
|||
- [Filtering Kotlin Collections](https://www.baeldung.com/kotlin-filter-collection)
|
||||
- [Collection Transformations in Kotlin](https://www.baeldung.com/kotlin-collection-transformations)
|
||||
- [Difference between fold and reduce in Kotlin](https://www.baeldung.com/kotlin/fold-vs-reduce)
|
||||
- [Guide to Sorting in Kotlin](https://www.baeldung.com/kotlin-sort)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
## Core Kotlin
|
||||
|
||||
This module contains articles about data structures in Kotlin
|
||||
|
||||
### Relevant articles:
|
||||
[Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree)
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-kotlin-datastructures</artifactId>
|
||||
<name>core-kotlin-datastructures</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-kotlin-modules</groupId>
|
||||
<artifactId>core-kotlin-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-runner</artifactId>
|
||||
<version>${junit.platform.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<junit.platform.version>1.1.1</junit.platform.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.binarytree
|
||||
package com.binarytree
|
||||
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
|
@ -0,0 +1,6 @@
|
|||
## Core Kotlin Date and Time
|
||||
|
||||
This module contains articles about Kotlin core date/time features.
|
||||
|
||||
### Relevant articles:
|
||||
[Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates)
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-kotlin-date-time</artifactId>
|
||||
<name>core-kotlin-date-time</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-kotlin-modules</groupId>
|
||||
<artifactId>core-kotlin-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${org.assertj.core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-runner</artifactId>
|
||||
<version>${junit.platform.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<junit.platform.version>1.1.1</junit.platform.version>
|
||||
<org.assertj.core.version>3.9.0</org.assertj.core.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
## Core Kotlin Design Patterns
|
||||
|
||||
This module contains articles about design patterns in Kotlin
|
||||
|
||||
### Relevant articles:
|
||||
- [Creational Design Patterns in Kotlin: Builder](https://www.baeldung.com/kotlin-builder-pattern)
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-kotlin-design-patterns</artifactId>
|
||||
<name>core-kotlin-design-patterns</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-kotlin-modules</groupId>
|
||||
<artifactId>core-kotlin-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-runner</artifactId>
|
||||
<version>${junit.platform.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<junit.platform.version>1.1.1</junit.platform.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue