I made a tool from a block I made no errors in code. When I try to click build it gives me this terminal error:
How can i fix this? Please.
Here is the code for the RecipesTools.addRecipes
package net.minecraft.src;
public class RecipesTools
{
private String recipePatterns[][] =
{
{
"XXX", " # ", " # "
}, {
"X", "#", "#"
}, {
"XX", "X#", " #"
}, {
"XX", " #", " #"
}
};
private Object recipeItems[][];
public RecipesTools()
{
recipeItems = (new Object[][]
{
new Object[] {
Block.planks, Block.cobblestone, Item.ingotIron, Item.diamond, Item.ingotGold, Block.RadiatedStone
}, new Object[] {
Item.pickaxeWood, Item.pickaxeStone, Item.pickaxeSteel, Item.pickaxeDiamond, Item.pickaxeGold, Item.pickaxeRadiated
}, new Object[] {
Item.shovelWood, Item.shovelStone, Item.shovelSteel, Item.shovelDiamond, Item.shovelGold
}, new Object[] {
Item.axeWood, Item.axeStone, Item.axeSteel, Item.axeDiamond, Item.axeGold
}, new Object[] {
Item.hoeWood, Item.hoeStone, Item.hoeSteel, Item.hoeDiamond, Item.hoeGold
}
});
}
public void addRecipes(CraftingManager craftingmanager)
{
for (int i = 0; i < recipeItems[0].length; i++)
{
Object obj = recipeItems[0][i];
for (int j = 0; j < recipeItems.length - 1; j++)
{
Item item = (Item)recipeItems[j + 1][i];
craftingmanager.addRecipe(new ItemStack(item), new Object[]
{
recipePatterns[j], Character.valueOf('#'), Item.stick, Character.valueOf('X'), obj
});
}
}
craftingmanager.addRecipe(new ItemStack(Item.shears), new Object[]
{
" #", "# ", Character.valueOf('#'), Item.ingotIron
});
}
}
EDIT
I also have given Eclipe 1024mb of RAM and deleted my .Minecraft folder.
CONFLICT # 22
27 achievements
Exception in thread "main" java.lang.ExceptionInInitializerError
at net.minecraft.src.StatList.initCraftableStats(StatList.java:74)
at net.minecraft.src.StatList.initBreakableStats(StatList.java:55)
at net.minecraft.src.Block.<clinit>(Block.java:975)
at net.minecraft.src.TextureWaterFX.<init>(TextureWaterFX.java:13)
at net.minecraft.client.Minecraft.<init>(Minecraft.java:205)
at net.minecraft.src.MinecraftImpl.<init>(MinecraftImpl.java:13)
at net.minecraft.client.Minecraft.startMainThread(Minecraft.java:1984)
at net.minecraft.client.Minecraft.startMainThread1(Minecraft.java:1970)
at net.minecraft.client.Minecraft.main(Minecraft.java:2032)
at Start.main(Start.java:25)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 5
at net.minecraft.src.RecipesTools.addRecipes(RecipesTools.java:44)
at net.minecraft.src.CraftingManager.<init>(CraftingManager.java:19)
at net.minecraft.src.CraftingManager.<clinit>(CraftingManager.java:8)
... 10 more
recipeItems[0].length is 6. But recipeItems[2] and the following only have five elements. Your toplevel loop in addRecipes it therefore wrong.
You should probably be using collection types (vector, list, Array, ...) and iterators for this, would make the code safer and more readable (IMO).
Your outer loop in addRecipies is iterating over the [0] array of recipeItems. In the first child array, there are 6 elements meaning that recipeItems[0][5] will be a valid item. But there is an incorrect assumption that this is true for all recipeItems arrays. At least one of the later arrays has fewer than 6 elements.
You should be iterating over the size of the child arrays rather than the size of the first array.
First of all, you should probably check of what type the Objects in the array are, before you cast them, so the part which currently is
Item item = (Item)recipeItems[j + 1][i];
in the loop, should be replaced with something like this:
Object itemObj = recipeItems[j + 1][i];
if(itemObj instanceof Item)
{
// The current element is an Item
Item item = (Item)recipeItems[j + 1][i];
craftingmanager.addRecipe(new ItemStack(item), new Object[]
{
recipePatterns[j], Character.valueOf('#'), Item.stick, Character.valueOf('X'), obj
});
}
else if(itemObj instanceof Block)
{
// The current element is a Block
Block block = (Block)recipeItems[j + 1][i];
craftingmanager.addRecipe(new ItemStack(block), new Object[]
{
recipePatterns[j], Character.valueOf('#'), Item.stick, Character.valueOf('X'), obj
});
}
else
{
// The current element is none of the types above
// TODO Throw an exception, print a message or quit the game
}
because, I'm pretty sure you can't cast an Item to a Block. This will not fix this problem, that was just a tip, because the code you used there before may cause errors in the future.
The solution to your current problem is what Mat and nicholas.hauschild has already answered. The first two elements of the recipeItems array (recipeItems[0] and recipeItems[1]) have 6 elements, but the rest of the elements have only 5 elements. In your loop, you only take the length of the first element and use it to loop through the rest of the elements too, but they are smaller than the first.
What happens if you try to acces element 6 in an array with 5 elements?
You could replace the loop with something like this:
for(int i = 0; i < recipeItems.length - 1; i++)
{
for(int j = 0; j < recipeItems[i].length; j++)
{
Object obj = recipeItems[0][j];
Object itemObj = recipeItems[i + 1][j];
if(itemObj instanceof Item)
{
// The current element is an Item
Item item = (Item)recipeItems[j + 1][i];
craftingmanager.addRecipe(new ItemStack(item), new Object[]
{
recipePatterns[j], Character.valueOf('#'), Item.stick, Character.valueOf('X'), obj
});
}
else if(itemObj instanceof Block)
{
// The current element is a Block
Block block = (Block)recipeItems[j + 1][i];
craftingmanager.addRecipe(new ItemStack(block), new Object[]
{
recipePatterns[j], Character.valueOf('#'), Item.stick, Character.valueOf('X'), obj
});
}
else
{
// The current element is none of the types above
// TODO Throw an exception, print a message or quit the game
}
}
}
Hope this helps!
Related
I am new to java but have been playing with array-lists and am now stuck.
I have an array list created off a class called Car with three parameters one of which is called times moved.
ArrayList:
private ArrayList<Car> list = new ArrayList<Car>() ;
Car class
public Car ( String licenseNum, String carStatus , int timesMoved)
{
licensePlate = licenseNum ;
status = carStatus ;
moved = timesMoved;
}
I am reading input of a file that is supposed to be like a garage and says if a car is "Arriving" or "Departing"
I am trying to write a code using an if statement that says if the status is "Departing" then the current element gets deleted the all elements in front of it add one to their "times moved parameter"
The part I am stuck on is the one where, based on the element getting deleted, all the elements in front of it in the array list add one to their "times moved" parameter.
Would anyone give me some advice on how it would be possible to do that?
I came up with this but it does not seem to work
public void carDepart()
{
for ( int i = 0 ; i < list.size() ; i++ )
{
Car current = list.get( i ) ; // get next car
if (current.getStatus().equals("DEPART"))
{
int pos = list.indexOf(i);
for ( int j = 0 ; pos < j ; j++)
{
current.setTimesMoved(1 + current.getTimesMoved());
}
list.remove(i);
}
break;
}
}
Second method
public void moveCarInGarage()
{
for ( int i = 0 ; i < list.size() ; i++ )
{
Car current = list.get( i ) ; // get next car
if (current.getStatus().equals("ARRIVE"))
{
currentCars++;
if (currentCars <= 10)
{
System.out.println("Car with license plate" +
current.getLicenseNum() + " has been moved into the garage");
}
else
{
System.out.println("The garage is full at this " +
"time so come back later");
}
}
else
{
currentCars--;
System.out.println("Car with license plate" +
current.getLicenseNum() + " is departing and has been moved "
+ current.getTimesMoved() + " times" );
}
}
}
Here is an example of what you can do. In it, I assume you are using getters and setters. You can also call the attributes directly assuming you've set the access modifiers in a way that allows you to do so.
All I did was create a new method called incrementTimesMoved() that iterates through your ArrayList and increments all the "moved" attributes in it's elements until it gets to the one with a given index. It removes this, and stops running.
public class MCVE {
public static void main(String[] args) {
// IMO list isn't very descriptive, so I changed it to carList.
ArrayList<Car> carList = new ArrayList<>();
// Add a bunch of values to carList here.
for(int i = 0; i < carList.size(); i++) {
if(carList.get(i).getStatus().equals("Departing")) {
incrementTimesMoved(i, carList);
return; // stops the method
}
}
}
// only static because I am calling in the main() function
private static void incrementTimesMoved(int index, ArrayList<Car> carList) {
for(int i = 0; i < carList.size(); i++) {
if(i == index) {
carList.remove(index);
return;
}
carList.get(i).setMoved(carList.get(i).getMoved() += 1);
}
}
}
This question already has answers here:
Why am I not getting a java.util.ConcurrentModificationException in this example?
(10 answers)
Closed 4 years ago.
If we write like this, there is a concurrent modification exception :
public static void main(String... args) {
List<String> listOfBooks = new ArrayList<>();
listOfBooks.add("Programming Pearls");
listOfBooks.add("Clean Code");
listOfBooks.add("Effective Java");
listOfBooks.add("Code Complete");
System.err.println("Before deleting : " + listOfBooks);
for (String book : listOfBooks) {
if (book.contains("Code")) {
listOfBooks.remove(book);
}
}
System.err.println("After deleting : " + listOfBooks);
}
On the other hand, if we write like this, there is NO concurrent modification exception !
Notice that code is exact the same, except the strings for compare, in first example it is a Code, and in second it is a Java
public static void main(String... args) {
List<String> listOfBooks = new ArrayList<>();
listOfBooks.add("Programming Pearls");
listOfBooks.add("Clean Code");
listOfBooks.add("Effective Java");
listOfBooks.add("Code Complete");
System.err.println("Before deleting : " + listOfBooks);
for (String book : listOfBooks) {
if (book.contains("Java")) {
listOfBooks.remove(book);
}
}
System.err.println("After deleting : " + listOfBooks);
}
I'm using Netbeans 8.2, Windows 7 32bit, with JDK 1.8.0_131
What's wrong ?
List.remove() will not throw ConcurrentModificationException when it removes the second last element from the list.
Quoting from this Java Bug (JDK-4902078) .
When the Collections Framework was added to the platform it was deemed too expensive to check for comodification once rather than twice per iteration; the check was made on Iterator.next rather than Iterator.hasNext. Expert reviewers thought this was sufficient. They were unaware that it fails to detect one important case: if an element is removed from the list immediately prior to the final call to hasNext in an iteration, the call returns false and the iteration terminates, silently ignoring the last element on the list.
You can also check this answer :-
https://stackoverflow.com/a/8189786/1992276
There are two ways used to iterate over an collection: enumeration and iterator.
First one allows for the collection to be modified during iteration (fail slow), second does not (fail fast). In a for-each loop you are using an iterator, so any modification to the collection, during it's iteration would cause an exception.
You have 3 choices, to solve this problem:
Use an iterator instead:
Iterator<String> bookIt = listOfBooks.iterator();
while(bookIt.hasNext()){
String book = bookIt.next();
if (book.contains("Java")) {
bookIt.remove();
}
}
Create a new list with only acceptable elements (filter out the unwanted):
List<String> booksWithNoCode = listOfBooks.stream()
.filter(book-> !book.contains("Code"))
.collect(toList())
Use Collection.removeIf(), you will remove all elements from the list, that are matching given criteria.
listOfBooks.removeIf(book-> book.contains("Code"))
You can find more information in this post and here.
You can't modify the listOfBooks while you are iterating though it with the for each loop.
edit:
for (String book : listOfBooks) {
if (book.contains("Code")) {
listOfBooks.remove(book);
}
}
Is the same as:
for (Iterator<String> i = listOfBooks.iterator(); i.hasNext();) {
String book = i.next();
if (book.contains("Code")) {
listOfBooks.remove(book);
}
}
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/ArrayList.java
The key in the arraylist code is:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
and the iterator code:
public boolean hasNext() {
return cursor != size;
}
#SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
The cursor always points to the next element so when you get the "Effective Java" i = 2 but cursor is 3.
When you call the remove the cursor is at 3 and the size is 4.
The size is then decremented by the remove and now cursor == size and the next hasNext() returns false ending the loop.
I am trying to create an array to post to my PHP api from my android application.
I have set up the php end to expect an array that matches this format:
$post = [
"checks" => [
[
"check_id" => $check->id,
"completed" => true
],
[
"check_id" => $checkTwo->id,
"completed" => true
]
]
];
So I need to recreate this on the java end.
I have an array of the checks which I am looping through:
for(DeviceCheck check : device.checks()){
}
And have tried to use JsonObjects and JsonArray but just can't get the end result I require.
I have also tried using Map like this:
Map<String, String> map = new HashMap<String, String>();
map.put("check_id", String.valueOf(checkId));
map.put("completed", String.valueOf(check.completed));
But then couldn't figure out how to apply this to the checks array that I need.
Any suggestions to get this?
Create a checks model.
class Checks {
String check;
boolean completed;
Checks (String check, boolean completed) {
this.check = check;
this.completed = completed;
}
public String getCheck() {
return check;
}
public void setCheck(String check) {
this.check = check;
}
public boolean getCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
}
Add items into your array... iterate through it, create a new object, insert items into object, add object to array.
List<Checks> list = new ArrayList<>();
list.add(new Checks("check1", true));
list.add(new Checks("check2", false));
list.add(new Checks("check3", false));
list.add(new Checks("check4", true));
list.add(new Checks("check5", true));
JSONObject object = new JSONObject();
JSONArray array = new JSONArray();
try {
for (int i = 0; i < list.size(); i++) {
JSONObject checkobjects = new JSONObject();
checkobjects.put("check_id", list.get(i).getCheck());
checkobjects.put("completed", list.get(i).getCompleted());
array.put(checkobjects);
}
object.put("checks", array);
} catch (JSONException e1) {
e1.printStackTrace();
}
System.out.println(object);
}
This will print the following:
{"checks":[
{"check_id":"check1","completed":true},
{"check_id":"check2","completed":false},
{"check_id":"check3","completed":false},
{"check_id":"check4","completed":true},
{"check_id":"check5","completed":true}
]}
Oh, and finally, if you want to get the information from the server object, you do the following...
try {
JSONArray getArr = object.getJSONArray("checks");
for (int i = 0; i < getArr.length(); i++) {
System.out.println("check_id: " + getArr.getJSONObject(i).getString("check_id") + " " + "completed: " + getArr.getJSONObject(i).getBoolean("completed"));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Doing that will print the following:
check_id: check1 completed: true
check_id: check2 completed: false
check_id: check3 completed: false
check_id: check4 completed: true
check_id: check5 completed: true
I have a json file that contains 500k Objects and this is its format:
"WORKORDER": [
{
"Attributes": {
"SITEID": {
"content": "BEDFORD"
},
"WONUM": {
"content": "1000"
},
"WOPRIORITY": {
"content": 2
},
"WORKTYPE": {
"content": "CM"
}
}
},
{
"Attributes": {
"SITEID": {
"content": "BEDFORD"
},
"WONUM": {
"content": "1000-10"
},
"WORKTYPE": {
"content": "CM"
}
}
}
Im geting the distinct values like this :
for (int i = 0; i < WORKORDER.length(); i++) {
JSONObject obj = WORKORDER.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if( att.has(col)){ // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if(!(list.contains(colval))) {
out.println( colval);
list.add(colval);
}
But it takes long time for only 5000 objects !
Is there any way to get the distinct values of any column without parsing the whole Json file, otherwise parsing only the column needed.
You are iterating on a JSON with 500k elements. For each element you check if it was previously added in a List. That means your logic will iterate the list 500k times.
Instead, you should use a HashSet, first, the Set prevent duplicated value. So you just need to set.add(value) but the most interesting is the fact that the instance have a constant complexity value. Since it used buckets to organize the value, it doesn't have to iterate the Set fully.
You can read more about that in amit answer's about How can a HashSet offer constant time add operation?
Note that HashSet gives amortized and average time performance of O(1), not worst case. This means, we can suffer an O(n) operation from time to time.
So, when the bins are too packed up, we just create a new, bigger array, and copy the elements to it.
Note that to use any Hash#### implementation, you need to make sure the instance you store implements hashCode and equals correctly. You can find out more about this in the community post about What issues should be considered when overriding equals and hashCode in Java?.
Now for the solution :
Set<Object> sets = new HashSet<>();
for (int i = 0; i < WORKORDER.length(); i++) {
// ...
Object colval = column.get("content");
if(sets.add(colval)){ //`add` return true if it wasn't present already.
out.println( colval);
}
}
I kept the Object type but this should be correctly typed, at least to be sure that those instance are implementing those methods as needed.
colval being an Object, it is possible it doesn't implements correctly the methods needed so I suggest you parse it correctly. You should use column.getString("content) instead or check the instance type.
To validate this, I have used a method to create a fake JSON:
public static JSONObject createDummyJson(int items) {
JSONObject json = new JSONObject();
JSONArray orders = new JSONArray();
json.put("order", orders);
JSONObject attributes;
JSONObject item;
JSONObject order;
Random rand = new Random();
String[] columns = {"columnA", "columnB", "columnC", "columnD"};
for(int i = 0; i < items; ++i) {
order = new JSONObject();
attributes = new JSONObject();
order.put("Attributes", attributes);
orders.put(order);
for(int j = 0; j < rand.nextInt(1000) % columns.length; ++j) {
item= new JSONObject();
long rValue = rand.nextLong();
item.put("content", j%3 == 0 ? ("" + rValue ) : rValue );
attributes.put(columns[j], item);
}
}
return json;
}
Then ran a basic benchmark for both method and had the following results :
public static void main(String[] args) throws Exception {
final int jsonLength = 500_000;
JSONObject json = createDummyJson(jsonLength);
long start = System.currentTimeMillis();
List<Object> list = parseJson(json);
long end = System.currentTimeMillis();
System.out.format("List - Run in %d ms for %d items and output %d lines%n", end-start, jsonLength, list.size());
start = System.currentTimeMillis();
Set<Object> set = parseJsonSet(json);
end = System.currentTimeMillis();
System.out.format("Set - Run in %d ms for %d items and output %d lines%n", end-start, jsonLength, set.size());
}
public static List<Object> parseJson(JSONObject json) {
String col = "columnC";
JSONArray array = json.getJSONArray("order");
List<Object> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if (att.has(col)) { // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if (!(list.contains(colval))) {
//System.out.println(colval);
list.add(colval);
}
}
}
return list;
}
public static Set<Object> parseJsonSet(JSONObject json) {
String col = "columnC";
JSONArray array = json.getJSONArray("order");
Set<Object> set = new HashSet<>();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if (att.has(col)) { // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if (set.add(colval)) {
//System.out.println(colval);
}
}
}
return set;
}
List - Run in 5993 ms for 500000 items and output 46971 lines
Set - Run in 62 ms for 500000 items and output 46971 lines
I even went to a JSON with 5M row (removed the List that would never end)
Set - Run in 6436 ms for 5000000 items and output 468895 lines
Important, remove the line that print in console every new insertion, it will reduce the execution time a bit.
This JSONAray:
"cows": [
{
"age": 972,
"name": "Betty"
"status": "publish",
"sticky": "pregnant"
},
{
"age": 977,
"name"; "Kate"
"status": "publish",
"sticky": "heat"
},
{
"age": 959,
"name": "Julie"
"site_age": 63178480,
"sticky": "Nursing"
},
...
}
that contains 20 objects. What I wanted is this: get 3 random objects out of the 20. And the ages of any of the three won't be a certain number say 961.
Currently this what I am doing:
private void parseCowsReq(JSONObject array) {
try {
for (int i = 0; i < 3; i++) {
int randumNum = getRandomCow(array);
JSONObject jsonObject = array.getJSONObject(randumNum);
String cowName = jsonObject.getString("name");
String cowStatus = jsonObject.getString("status");
Log.d(TAG, "Cow name is " + cowName + "cow Status is " + cowStatus);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private int getRandomCow(JSONArray jsonArray) {
int length = jsonArray.length();
int[] array;
array = new int[length-1];
int rnd = new Random().nextInt(array.length);
return array[rnd];
}
There are of issues with this code.
I don't know how to ensure that the object gotten in line
JSONObject jsonObject = array.getJSONObject(randumNum); won't have an
age of 961
The random number gotten is always 0
Please do you have any idea how this can be done?
you can do it with this:
public ArrayList<Integer> getRandomObject(JSONArray jsonArray, int indexesWeeNeed){
Random rn = new Random();
Set<Integer> generated = new LinkedHashSet<>();
while(generated.size() < indexesWeeNeed){
int index = rn.nextInt(10);
JSONObject jsonObject = (JSONObject) jsonArray.get(index);
int age = jsonObject.getInt("age");
if(age<961) {
generated.add(index);
}
}
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.addAll(generated);
return arrayList;
}
One part that's messed up is when you call
Random().nextInt(array.length);
array.length is the new array you just created. You need to perform the function on the existing array:
Random().nextInt(jsonArray)
to get a random number other than zero.
As for ensuring you don't get a certain age, I'd suggest breaking up the code to not call the getRandomCow(array) function inside of the for loop. When you retrieve a cow, check the name doesn't match, check the age, and if it works, keep it. If not get another cow.
Well firstly, load the objects:
JSONArray array = /* your array */;
Next, we need a method to retrieve 3 unique objects from the JSONArray (which is actually a List). Let's shuffle the indexes of the json array, so that we don't end up having to repeatedly generate duplicates:
public Stream<JSONObject> randomObjects(JSONArray array, int amount) {
if (amount > array.size()) {
//error out, null, return array, whatever you desire
return array;
}
List<Integer> indexes = IntStream.range(0, array.size()).collect(Collectors.toList());
//random, but less time generating them and keeping track of duplicates
Collections.shuffle(indexes);
Set<Integer> back = new HashSet<>();
Iterator<Integer> itr = indexes.iterator();
while (back.size() < amount && itr.hasNext()) {
int val = itr.next();
if (array.get(val).getInt("age") != 961) { //or any other predicates
back.add(val);
}
}
return back.stream().map(array::get);
}
Using this, we can select the three objects from the list and utilize them how we wish:
randomObjects(array, 3).map(o -> o.getInt("age")).forEach(System.out::println);
//972
//977
//952
When I said "or any other predicates, you can pass those as well via the method:
public Stream<JSONObject> randomObjects(..., Predicate<Integer> validObject) {
//...
int val = itr.next();
if (validObject.test(val)) {
back.add(val);
}
//...
}
Which would mean you could change the blacklisting per method call:
Stream<JSONObject> random = randomObjects(array, 3, val -> array.get(val).getInt("age") != 961);