|
28 | 28 | import com.mitsuki.jmatrix.core.MatrixUtils;
|
29 | 29 |
|
30 | 30 | import java.util.Arrays;
|
| 31 | +import java.util.ArrayList; |
| 32 | +import java.util.Collections; |
| 33 | +import java.util.List; |
| 34 | +import java.util.stream.Collectors; |
31 | 35 |
|
32 | 36 | /**
|
33 | 37 | * The <b>Matrix</b> class represents a two-dimensional (2D) array of {@code double}s.
|
@@ -2870,15 +2874,15 @@ public static boolean isSparse(Matrix m) {
|
2870 | 2874 | "Matrix is null. Please ensure the matrix have been initialized.")
|
2871 | 2875 | );
|
2872 | 2876 | }
|
2873 |
| - |
| 2877 | + |
2874 | 2878 | for (int r = 0; r < mSize[0]; r++) {
|
2875 | 2879 | for (int c = 0; c < mSize[1]; c++) {
|
2876 | 2880 | if (Math.abs(m.get(r, c)) > Matrix.THRESHOLD) {
|
2877 | 2881 | numberNonZero++; // increment
|
2878 | 2882 | }
|
2879 | 2883 | }
|
2880 | 2884 | }
|
2881 |
| - |
| 2885 | + |
2882 | 2886 | return (numberNonZero <= Math.max(mSize[0], mSize[1]));
|
2883 | 2887 | }
|
2884 | 2888 |
|
@@ -3651,24 +3655,85 @@ public static double getEntry(Matrix m, int row, int col) {
|
3651 | 3655 |
|
3652 | 3656 |
|
3653 | 3657 | /**
|
3654 |
| - * Returns the {@code double} two-dimensional array representation of this matrix elements. |
| 3658 | + * Retrieves a two-dimensional array representing the elements of this matrix, |
| 3659 | + * preserving data integrity. |
3655 | 3660 | *
|
3656 |
| - * <p><b>Note:</b></p> |
3657 |
| - * If the matrix constructed by using {@link #Matrix()} constructor, |
3658 |
| - * this method would returns {@code null} instead (similar with the entries). |
| 3661 | + * <p>If the matrix was constructed using the default {@link #Matrix()} constructor |
| 3662 | + * without any explicit entries, this method returns {@code null}, indicating that |
| 3663 | + * the matrix has not been initialized with any data. To determine whether a matrix |
| 3664 | + * has uninitialized ({@code null}) entries, use the |
| 3665 | + * {@link MatrixUtils#isNullEntries(Matrix)} helper method. |
3659 | 3666 | *
|
3660 |
| - * @return A two-dimensional array that represents entries of this matrix, |
3661 |
| - * returns {@code null} instead if the entries is uninitialized. |
| 3667 | + * <p><b>Implementation Note:</b></p> |
| 3668 | + * <p>As of version 1.5.0, this method would returns a deep copy of the internal |
| 3669 | + * matrix entries instead of returning the object reference of the entries itself |
| 3670 | + * (see <a href="https://github.com/mitsuki31/jmatrix/issues/103">#103</a>), |
| 3671 | + * this ensuring that modifications to the returned array do not affect |
| 3672 | + * the original matrix data. This is essential for preventing unintended side |
| 3673 | + * effects and maintaining data consistency. |
| 3674 | + * |
| 3675 | + * @return A two-dimensional array of {@code double} values representing the |
| 3676 | + * matrix entries, or {@code null} if the matrix is uninitialized. |
3662 | 3677 | *
|
3663 | 3678 | * @since 1.0.0b.5
|
3664 |
| - * @see #get(int, int) |
3665 |
| - * @see #getSize() |
| 3679 | + * @see #getReadOnlyEntries() |
3666 | 3680 | * @see MatrixUtils#isNullEntries(Matrix)
|
3667 | 3681 | */
|
3668 | 3682 | public double[ ][ ] getEntries() {
|
3669 |
| - // TODO: Fix the shallow copy of the returned array |
3670 |
| - // Here will lead to shallow copy of the entries array. |
3671 |
| - return this.ENTRIES; |
| 3683 | + return MatrixUtils.deepCopyOf(this.ENTRIES); |
| 3684 | + } |
| 3685 | + |
| 3686 | + /** |
| 3687 | + * Obtains a read-only view of the matrix elements, safeguarding against |
| 3688 | + * unintended modifications. |
| 3689 | + * |
| 3690 | + * <p>This method offers a secure way to access the matrix elements without |
| 3691 | + * the risk of unintended modifications. This method returns a list of lists, |
| 3692 | + * where each inner list represents an immutable row of the matrix, ensuring |
| 3693 | + * data integrity and preventing accidental changes. Attempting to modify the |
| 3694 | + * elements will causing the method to throws an exception |
| 3695 | + * {@code UnsupportedOperationException}. If you want to get the matrix |
| 3696 | + * elements but can still access and modify each elements, consider to use the |
| 3697 | + * {@link #getEntries()} method instead. |
| 3698 | + * |
| 3699 | + * <p><b>Implementation Note:</b></p> |
| 3700 | + * <p>The method leverages the {@code Arrays.stream} API introduced in Java 8. |
| 3701 | + * This allows for concise and efficient conversion of primitive {@code double} |
| 3702 | + * arrays to {@code Double} objects and subsequent creation of unmodifiable |
| 3703 | + * lists. However, it's crucial to note that this approach might not be |
| 3704 | + * compatible with older Java versions that lack {@code Arrays.stream} functionality. |
| 3705 | + * |
| 3706 | + * @return An unmodifiable view list of lists containing the matrix entries. |
| 3707 | + * Each inner list represents a single row of the matrix, containing |
| 3708 | + * {@code Double} objects instead of primitive {@code double} values. |
| 3709 | + * |
| 3710 | + * @throws NullMatrixException If the entries of this matrix is {@code null} |
| 3711 | + * or this matrix has not been initialized. |
| 3712 | + * |
| 3713 | + * @since 1.5.0 |
| 3714 | + * @see #getEntries() |
| 3715 | + */ |
| 3716 | + public List<List<Double>> getReadOnlyEntries() { |
| 3717 | + if (MatrixUtils.isNullEntries(this)) { |
| 3718 | + JMatrixUtils.raiseError(new NullMatrixException( |
| 3719 | + "Matrix is null. Please ensure the matrix are initialized.")); |
| 3720 | + } |
| 3721 | + |
| 3722 | + final int rows = this.getNumRows(); // Get the rows size |
| 3723 | + final List<List<Double>> readonlyEntries = new ArrayList<>(rows /* initial size */); |
| 3724 | + |
| 3725 | + for (int i = 0; i < rows; i++) { |
| 3726 | + // Convert the double (primitive type) array to list of Double (class type) |
| 3727 | + List<Double> thisRow = Arrays.stream(this.ENTRIES[i]) |
| 3728 | + .boxed() |
| 3729 | + .collect(Collectors.toList()); // Convert to List |
| 3730 | + // Lock each row and make it unmodifiable |
| 3731 | + readonlyEntries.add(Collections.unmodifiableList(thisRow)); |
| 3732 | + } |
| 3733 | + |
| 3734 | + // For the last touch, lock entirely the entries |
| 3735 | + // and return the read-only entries |
| 3736 | + return Collections.unmodifiableList(readonlyEntries); |
3672 | 3737 | }
|
3673 | 3738 |
|
3674 | 3739 |
|
|
0 commit comments