Effective Java Item42, at least one input argument - java

Effective java 2, Item 42 propose an elegant way for a method take at least one argument, and fail at compile time if the input is empty. The code is shown below in the min() method, however I am wondering what is the elegant way to call this method, because now simply passing list will trigger an compiler error.
public class OneOrMoreArgs {
public static int min(int firstArg, int... remaining){
// but then how do you call the function with a int[] ?
int _min = firstArg;
for(int x: remaining){
if(_min < x ){
_min = x;
}
}
return _min;
}
public static int sum(int... list){
int s = 0;
for(int a: list){
s += a;
}
return s;
}
public static void main(String []args){
int[] list = {1,2,3,4,5};
System.out.println(OneOrMoreArgs.sum(list));
System.out.println(OneOrMoreArgs.min(list));
}
}

Well, the elegant way to call it would be to do
OneOrMoreArgs.min(1, 2, 3, 4, 5);
If you need to pass in an array, you could add an additional method signature like this:
public static int min(int[] args){
if (args == null || args.length < 1) {
throw new IllegalArgumentException("... some error message...");
}
return min(args[0], Arrays.copyOfRange(args, 1, args.length));
}
It needs to be noted that:
This solution is inefficient as it requires the array to be copied.
The check is executed at runtime instead of compile time, so you lose the benefits of the solution proposed by Item 42.
It looks like for your use case, you're better off just declaring a method that takes an array parameter, like the sum() in your example.

Related

How do I make an array parameter in java?

I tried to make a parameter for an array for a method, but it always comes up with an error.
public void methodExample1() {
int array1[] = new int[4]
}
public void methodExample(Array array1[]) {
System.out.println(array1[0]);
}
But it always says there's an error in my parameter. Is there any way to do this?
Try this:
public void methodExample(int[] array1)
Explanation: The type is the same that you used for declaring a value that will be passed as parameter (for the moment I'm ignoring covariant arrays), for instance if you do this:
int[] array1 = new int[4];
... Then, at the time of passing it as a parameter we'll write it like this:
methodExample(array1)
Also notice that the size of the array must not be passed as parameter, and that by convention the [] part goes right after the type of the array's elements (in fact, int[] is the type of the array), and not after the array's name.
If I understand your question, then you could use Array, and something like
public static void methodExample(Object array1) {
int len = Array.getLength(array1);
for (int i = 0; i < len; i++) {
System.out.printf("array1[%d] = %d%n", i, Array.get(array1, i));
}
}
public static void main(String[] args) {
methodExample(new int[] { 1, 2, 3 });
}
Output is
array1[0] = 1
array1[1] = 2
array1[2] = 3
I assume that you are trying to pass array as a parameter to a method , to initialize it and then call another method to print it?
In java you have to create an object and "allocate" memory space for it by calling to new ...
so you can do like that :
public static void main(String[] args) {
int [] m_array; // creating a array reference
m_array = new int[5]; // allocate "memory" for each of of them or you can consider it as creating a primitive of int in each cell of the array
method(m_array); // passing by value to the method a reference for the array inside the method
}
public void method(int [] arr) // here you are passing a reference by value for the allocated array
{
System.out.println(arr[0]);
}

Adding numbers to arrays with methods in another class?

I am learning java and trying to figure out how to implement these methods into my main class from a second class. The program takes user input to add numbers into an array and then I need to print the following using the pre-specified methods below. The parameters in the below method is what confuses me.
public static double findMin(double[] numbers, int count) //count is the count of numbers stored in the array
public static double computePositiveSum(double[] numbers, int count)
public static int countNegative(double[] numbers, int count)
Basically, I am confused as to how I link all the variables and array between the two classes so they can recognize the parameters and return the correct value to output min, sum and number of negatives. Do I want the array in the main method?
Basically, what I did now to fix it was that I created the variables in the main method and then pass the variables in the main method through the parameters of the object I created that links to the secondary class. Does that seem ok?
If you already have the array , so what you need is call your methods and pass this value to it
lets say you have this array :
double[] num = {1.2,2.3};
and your count is the length of num array , so the count is:
int count = num.length;
then call your method and pass the parameters to it like this:
findMin(num , count );
computePositiveSum(num , count );
countNegative(num , count );
Note : you need to read in Object-Oriented Programming Concepts
Sorry guys for such a question. I just needed a refresher since it has been awhile. I resolved the issue by creating the array and count variable in the main method and then passed those through the parameters so the methods in the secondary class could read them. Thanks for the quick responses and help .
You don't need a count variable, you can use myarray.length
So your code should be something like this:
public static void main(string [] args)
{
double[] myarray = {5.3, 69.365, 125, 2.36};
double result = MyClass.findMin(myarray);
}
public class MyClass
{
public static double findMin(double[] numbers)
{
// your impl
}
public static double computePositiveSum(double[] numbers)
{
// your impl
}
public static int countNegative(double[] numbers)
{
// your impl
}
}
You can create an object reference of the main class in your derived class. Then call these methods using the object of your main class.
class Main
{
------
}
class derived
{
Main m = new Main();double[] A=new double[1];
Scanner s = new Scanner(System.in);
int i=0,wc=1;
int arrayGrowth=1;
while(s.hasNext())
{
if (A.length == wc) {
// expand list
A = Arrays.copyOf(A, A.length + arrayGrowth);
wc+=arrayGrowth;
}
A[i]=s.nextDouble();
i++;
}
int len=A.length-1;
m.findMin(A,len);
m.computePositiveSum(A,len);
m.countNegative(A,len);
}

Reversing integer array

Just curious, but when I try to use this to reverse an array it always spits out some incoherent gibberish instead of the array reversed, such as [I#43256ea2. Any ideas as to why it does this?
public class Fiddle {
public static void main(String[] args) {
int[] number = {1,2,3,4,5};
System.out.println(reverse(number));
}
public static int[] reverse(int[] a) {
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[a.length-1-i] = a[i];
}
return b;
}
}
Thanks for any ideas as to why this is happening (it's probably because I'm forgetting something though).
Use the utility method java.util.Arrays.toString(int[]):
System.out.println(Arrays.toString(reverse(number)));
Array classes do not override Object.toString(), meaning they use the default implementation provided by Object, which is "type#hashcode_in_hex". The String representation of the type int[] is [I, which is why you are seeing this "incoherent gibberish."
Try this:
System.out.println(Arrays.toString(reverse(number)));
It's one of the "mistakes" of java - you have to use Arrays.toString() otherwise you get the default toString() from Object, which produces output like you're seeing,
You are printing the hash of the array. you should do something like
for(int i: reverse(number)){
System.out.println(i);
}
Commons.lang
ArrayUtils.reverse(int[] array)
Done.

Varargs, immutable array, and thread-safety

Hi all I have an immutable array implementation which looks like this:
public static final class FixedArray<T> {
private final T[] array;
public final int Length;
#SafeVarargs
public FixedArray(T... args) {
array = args;
Length = args.length;
}
public T Get(int index) {
return array[index];
}
}
public static final class FixedIntArray {
private final int[] array;
public final int Length;
public FixedIntArray(int... args) {
array = args;
Length = args.length;
}
public int Get(int index) {
return array[index];
}
}
public static final class FixedLongArray {
private final long[] array;
public final int Length;
public FixedLongArray(long... args) {
array = args;
Length = args.length;
}
public long Get(int index) {
return array[index];
}
}
Initially I'd thought that it is guaranteed to be thread-safe. But after reading the discussion regarding immutable arrays and the Java Memory Model, I believe alone, I can't be sure.
I've not used a defensive copy, with the contract that the calling code "does the right thing" (and as usual, if it doesn't follow the contract, the behavior is undefined).
The calling method looks like this:
public static void main(String args[]) {
int[] ints = new int[10000];
FixedIntArray fixed_ints = new FixedIntArray(ints);
SendToThreadA(fixed_ints);
SendToThreadB(fixed_ints);
SendToThreadC(fixed_ints);
SendToThreadD(fixed_ints);
//caller (which is this method) does the right thing, ints goes out of scope without anyone trying to modify it.
}
I was wondering is the code above guaranteed to be thread-safe?
As we don't know what happens to the array (and its values) to which you store a reference, I think your classes would be much safer if the constuctors create a copy of the argument array and set the internal final reference to the copied array.
It's OK. You can require caller to "hand-off" the array to you. Caller can clone one if necessary.
Memory write is usually the most expensive thing in a program (sans external IO).
Not everybody is stupid. You only need to be defensive enough to protect your target user base.
Given that you can pass an array to a varargs method, you'd need to make a copy of the constructor input to ensure it can't be modified outside the class. Having done that, as long as you don't assign the final field until after all the values are assigned in the copy array, you should be fine because the assignment to the final field is guaranteed to happen before any read of that field from another thread.
So a constructor would look like:
array = Arrays.copyOf(args, args.length);
Orrrr you could just use a Guava ImmutableList and get a lot more power.
I'm not sure it's meaningful to examine it for thread-safety, because it's missing even a more basic level of safety. Consider this method:
public static void main(final String... args)
{
final int[] arr = new int[] { 3, 3, 3 };
final FixedIntArray threeThrees = new FixedIntArray(arr);
System.out.println(threeThrees.Get(0)); // prints "3"
System.out.println(threeThrees.Get(1)); // prints "3"
System.out.println(threeThrees.Get(2)); // prints "3"
arr[0] = arr[1] = arr[2] = 4;
System.out.println(threeThrees.Get(0)); // prints "4"
System.out.println(threeThrees.Get(1)); // prints "4"
System.out.println(threeThrees.Get(2)); // prints "4"
}
The problem is that, when a method that takes int... (or Object... or long... or anything else), it can receive either an array that's implicitly constructed by the compiler (as would happen if you typed new FixedIntArray(3,3,3)), or an array that's explicitly passed in by the calling code (as I did above). In the latter case, the calling code can continue to modify the array that it passed in!

Modify an array passed as a method-parameter

Suppose I have an int-array and I want to modify it. I know that I cannot assign a new array to array passed as parameter:
public static void main(String[] args)
{
int[] temp_array = {1};
method(temp_array);
System.out.println(temp_array[0]); // prints 1
}
public static void method(int[] n)
{
n = new int[]{2};
}
while I can modify it:
public static void main(String[] args)
{
int[] temp_array = {1};
method(temp_array);
System.out.println(temp_array[0]); // prints 2
}
public static void method(int[] n)
{
n[0] = 2;
}
Then, I tried to assign an arbitrary array to the array passed as parameter using clone():
public static void main(String[] args)
{
int[] temp_array = {1};
method(temp_array);
System.out.println(temp_array[0]); // prints 1 ?!
}
public static void method(int[] n)
{
int[] temp = new int[]{2};
n = temp.clone();
}
Now, I wonder why it prints 1 in last example while I'm just copying the array with clone() which it's just copying the value not the reference. Could you please explain that for me?
EDIT: Is there a way to copy an array to object without changing the reference? I mean to make last example printing 2.
Your examples 1 and 3 are virtually the same in context of the question - you are trying to assign a new value to n (which is a reference to an array passed by value).
The fact that you cloned temp array doesn't matter - all it did was create a copy of temp and then assign it to n.
In order to copy values into array passed into your method method you might want to look at:System.arraycopy
It all, of course, depends on the sizes of your n array and the one you create inside method method.
Assuming they both have the same length, for example, you would do it like that:
public static void main(String[] args)
{
int[] temp_array = {1};
method(temp_array);
System.out.println(temp_array[0]);
}
public static void method(int[] n)
{
int[] temp = new int[]{2};
System.arraycopy(temp, 0, n, 0, n.length);
// or System.arraycopy(temp, 0, n, 0, temp.length) -
// since we assumed that n and temp are of the same length
}
In your method
public static void method(int[] n)
n is another name for the array that way passed in. It points to the same place in memory as the original, which is an array of ints. If you change one of the values stored in that array, all names that point to it will see the change.
However, in the actual method
public static void method(int[] n) {
int[] temp = new int[]{2};
n = temp.clone();
}
You're creating a new array and then saying "the name 'n' now points at this, other array, not the one that was passed in". In effect, the name 'n' is no longer a name for the array that was passed in.
As you correctly note, you cannot assign to the array reference passed as a parameter. (Or more precisely, the assignment won't have any effect in the caller.)
This is about the best that you can do:
public static void method(int[] n) {
int[] temp = new int[]{2};
for (int i = 0; i < temp.length; i++) {
n[i] = temp[i];
}
// ... or the equivalent using System.arraycopy(...) or some such
}
Of course, this only works properly if the size of the input array is the same as the size of the array you are copying to it. (How you should deal with this will be application specific ...)
For the record Java passes the array reference by value. It doesn't pass the array contents by value. And clone won't help to solve this problem. (At least, not with the method signature as declared.)
In your method method, nothing that you assign to n will ever change the value of the object passed in and assigned to n. At the beginning of method, n points to an array. When you assign n to equal another array, you've simply re-pointed which array n points to, and haven't changed anything about temp_array from the main method.

Categories